-2

EDIT: I would like to have one function being called and executed after one second of the last keyup event.

Here's my code: http://jsfiddle.net/gKkAQ/

JS:

function aFunction() {
    setTimeout(function () {
        console.log("1");
    }, 1000);
}

$(document).ready(function () {
    $("#Input").keyup(function () {
        aFunction();
    });
});

HTML:

<input type="text" id="Input"></input>

You can easily run the JSFiddle and see in your console that no matter how fast you type, the function will be executed regardless of its previous execution status (in this case, setTimeout is not done yet in 1 second, but if you keep typing, ALL function calls will be executed)

Jin Wang
  • 254
  • 1
  • 7
  • 19
  • 2
    Unless the function does something asynchronously, this already happens. – Ian Aug 18 '13 at 05:12
  • If you describe more what happens inside the function the question will be more clear. – Sergio Aug 18 '13 at 05:17
  • @Sergio my code is added – Jin Wang Aug 18 '13 at 05:34
  • @Ian It will be executed for whatever times you call it... – Jin Wang Aug 18 '13 at 05:35
  • @TheJinStudio Like I said, unless it has asynchronous code, you can't "interrupt" a function. And as you've posted, your code **does** have asynchronous behavior – Ian Aug 18 '13 at 05:36
  • Do you mean something like this: http://jsfiddle.net/jRLa3/ ? – Ian Aug 18 '13 at 05:39
  • Your `aFunction()` function will not be interrupted by other code or run more than once simultaneously, no matter how fast or slow you type. The anonymous function you pass to `setTimeout()` will always be executed _later,_ `aFunction()` doesn't ever wait for it. What are you actually trying to achieve here? – nnnnnn Aug 18 '13 at 05:41
  • @nnnnnn I think the OP wants to prevent the `setTimeout` to execute if a previous `setTimeout` is still waiting the 1000ms – Ian Aug 18 '13 at 05:43
  • @Ian It's very close to what I want. But if you keep typing, you will see the function being executed every second. I would like it to be executed after one second of the last keyup action. – Jin Wang Aug 18 '13 at 05:43
  • 1
    @TheJinStudio Well then you should've said that, because that's totally different :) – Ian Aug 18 '13 at 05:44
  • @nnnnnn I am trying to have this function executed after one second of the last keyup event. – Jin Wang Aug 18 '13 at 05:45
  • @Ian I think you are right. I realized the question I'm posting is for something different than what I want to achieve.. Let me edit it. – Jin Wang Aug 18 '13 at 05:46
  • @TheJinStudio Good idea :) I think nnnnnn's answer is what you're looking for – Ian Aug 18 '13 at 05:47
  • Hmmm. Why is my question voted down? – Jin Wang Aug 18 '13 at 05:59
  • I don't see any relationship at all between the original question and what resulted from the edits. Besides a -1 to the question, The Jin Studio is now in my black list because just made me waste at least 20 minutes of my time. – Mario Rossi Aug 18 '13 at 05:59
  • 1
    @MarioRossi All I can say is "wow." Well thanks for your answer anyway. – Jin Wang Aug 18 '13 at 06:02

2 Answers2

3

"you will see the function being executed every second. I would like it to be executed after one second of the last keyup action"

The setTimeout() function returns an id that you can pass to clearTimeout() to prevent the timeout from occurring - assuming of course that you call clearTimeout() before the time is up.

var timeoutId;
function aFunction() {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(function () {
        console.log("1");
    }, 1000);
}

$(document).ready(function () {
    $("#Input").keyup(function () {
        aFunction();
    });
});

There is no harm in calling clearTimeout() with the id of a timeout that did already happen, in that case it has no effect.

So the above code clears the previous timeout (if there is one) and then creates a new one, with the effect that the anonymous function with the console.log() will only be execute 1000ms after the user stops typing. If the user starts typing again after waiting more than 1000ms that will queue up another timeout.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • 1
    Thanks @Ian, you saved me some effort. – nnnnnn Aug 18 '13 at 05:52
  • +1 This works for me. Well, then I searched to put a delay during the keyup event before calling the function. I got this: http://stackoverflow.com/questions/1909441/jquery-keyup-delay – Jin Wang Aug 18 '13 at 05:56
0

NOTE: THIS ANSWER CORRESPONDS TO THE INITIAL, VERY GENERAL QUESTION, BEFORE IT WAS SUBJECT TO EXTENSIVE EDITING AND TRANSFORMED IN A VERY SPECIFIC ONE.

It depends on your exact execution environment. Theoretically, JavaScript is single-threaded. The situation you describe should never happen. In practice, however, it does happen (especially inside browsers), and there is no way to fully control it.

The closest alternative to "control" is to start by checking the value of a global "activation counter" variable. If it is 0, immediately increment it and proceed with execution. Decrement it when exiting.

Why this doesn't work? Because 2 activations can reach the test at the same time. As the variable is 0, both tests will succeed and both will procceed to increment the variable and execute. As with most syncronization/concurrency issues, problems will not occurr systematically, but randomly every now and then. This makes things difficult to detect, reproduce and correct.

You can try to ask two times for the variable, as in:

if( activationCounter <= 0 ) {
    if( activationCounter <= 0 ) {
        activationCounter++;
        //  Execution
        activationCounter--;
    }
}

In many circles this has been described as a solution to the problem, but it only reduces the probability of conflict (by quite a bit, but not to zero). It's just the result of a bad understanding of the "double-checked locking" pattern. Problems will still occur, but with much less frequency. I'm not sure if this is good or bad, as they will be even more difficult to detect, reproduce and correct.

Mario Rossi
  • 7,651
  • 27
  • 37
  • Indeed, JavaScript has no facilities to be thread safe. This can be done safely however, using a technique in Dijkstra's `Cooperating Sequential Processes', found in any Operating Systems textbook. I am not suggesting you actually implement Dijkstra's algorithm: just use it for a reference but spend most of your effort reconsidering your approach so that tweaks like this are not necessary. – alexsh Aug 18 '13 at 05:41
  • Dijkstra's recognizes the need from synchonization primitives. If you don't have the primitives, then there is nothing you can do (but throw the dice). One of the simplest synchonization primitives is `test and set` or `test and increment`. This looks something like `if( var++ == 0 )`. We could say "Oh, but most languages support that". Problem is we would be forgetting the small letter: the test and the increment **must** occur as a single, indivisible, uninterruptible operation. "Rapid succession" may work most of the time, but is not a real solution. – Mario Rossi Aug 18 '13 at 05:56
  • The nested `if` statements are unnecessary. JavaScript **is** single-threaded, and there's no way for two executions to be occurring at the same time (to modify this shared variable). This might be the case in other languages, but isn't applicable here. Other than that, your increment/decrement (which could be resolved to a boolean flag instead) seems like a good solution to the original question. – Ian Aug 18 '13 at 06:51
  • @Ian If JavaScript were single-threaded in all environments (which in practice is **not**), *no* `if` at all would be necessary. No flag, no counter, nothing (unless what you want to prevent is direct or indirect recursion, but that's a completely different animal). – Mario Rossi Aug 18 '13 at 07:36
  • @MarioRossi I think you're misunderstanding the asynchronous behavior of JavaScript with other languages. And yes, JavaScript is single-threaded in all browsers. The area where it isn't, is with Web Workers, which actually creates new threads to execute at the same time as the main thread, but are completely thread-safe. The way asynchronous things work in JavaScript (like `setTimout`, `setInterval`, event handlers, etc.) are that they are scheduled to execute at a specific time. When that time comes, **and** when there is no other JavaScript execution, it executes. There's no conflicts there – Ian Aug 18 '13 at 07:51