javascript SetTimeout only invoked at function exit - javascript

I've noticed that setTimeout(function, milliseconds)
when used in middle of function will only be executed once function has ended regardless of timming given to it,
for example:
function doStuff(){
var begin = (new Date()).getTime();
console.log(begin);
setTimeout(function(){console.log("Timeout");},100);
doWork(4000);
var end = (new Date()).getTime();
console.log(end);
console.log("diff: "+(end-begin));
}
function doWork(num){
for(;num>0;--num) console.log("num");
}
doStuff();
the code above sets the timeout for 100 milliseconds but it is invoked only after all function completes which is much more then 100 milliseconds,
my question is:
why does this happen ?
how can i insure correct timing ?

JavaScript is not pre-emptive: it first finishes what it is doing before looking what is the next task that was posted in the queue (functions submitted for asynchronous execution). So even if a time-out expires, this will not influence the currently running code -- it does not get interrupted. Only when the stack of currently running functions have all returned and nothing remains to be run, JavaScript will check if there is a time-out request to be fulfilled, or whatever else is first in the queue.
From "Concurrency model and Event Loop" on MDN:
Queue
A JavaScript runtime contains a message queue, which is a list of messages to be processed. A function is associated with each message. When the stack is empty, a message is taken out of the queue and processed. The processing consists of calling the associated function (and thus creating an initial stack frame). The message processing ends when the stack becomes empty again.
Event loop
The event loop got its name because of how it's usually implemented, which usually resembles:
while(queue.waitForMessage()){
queue.processNextMessage();
}
queue.waitForMessage waits synchronously for a message to arrive if there is none currently.
"Run-to-completion"
Each message is processed completely before any other message is processed. This offers some nice properties when reasoning about your program, including the fact that whenever a function runs, it cannot be pre-empted and will run entirely before any other code runs (and can modify data the function manipulates). This differs from C, for instance, where if a function runs in a thread, it can be stopped at any point to run some other code in another thread.
A downside of this model is that if a message takes too long to complete, the web application is unable to process user interactions like click or scroll. The browser mitigates this with the "a script is taking too long to run" dialog. A good practice to follow is to make message processing short and if possible cut down one message into several messages.
To get code to run concurrently, you can make use of Web Workers. Web Workers run scripts in different threads.

Related

Single thread Javascript and AJAX handling

Javascript is said to be single-threaded. Also AJAX is said to be asynchronous.
Consider a scenario;
I have a button and on click of it, I make a AJAX call which takes 5-6 seconds. Now the UI would not be blocked and the user does some other action (say click on another button which is now executing some code, while the AJAX response has been returned). Now in this case, since the other code is being executed, when would the AJAX callback be executed? Would it have to wait OR can it be executed in a parallel thread ?
The events are queued, so when the Ajax call completes, the handler for that would be queued to run on the event loop. When the single thread is done with your button handler, it'll then process the next event in the queue. So - you would have to wait for the code kicked off by the button click to finish, unless of course the Ajax request completed before the user clicked on the button, in which case the button click handler had to wait. The best you can do is split up your algorithm so that it runs in discrete chunks, these can be dropped onto the queue using setTimeout, but that is quite tricky.
So I have searched a little about this topic in general. Contrary to what I have imagined, javascript is nothing like multi-threaded. Instead, it has a queue of operations it performs.
The direct answer then is: Depending on the very exact timing, the AJAX callback might have to wait before click event completes. It also might have to wait for any other code that was executed at "the same moment".
This explains while things like while(true) or alert() stop every script on the site.

JavaScript callbacks and control flow

When are callbacks executed, for example the callback of a setTimeout() or a click event?
Do they pause code, that is already running, or do they wait until it has finished?
Example
I have a data structure (incrementalChanges) that records state changes caused by user interactions, for example mouse clicks. If I want to send all changes to another peer, I send him this data structure.
Another possibility is a full synchronisation (makeFullSync()), that means I send him my complete current state, so that I must empty the incremental changes (deleteIncrementalChanges()). That is, what you can see in the code. However I am not sure, what happens, if a user clicks something exactly between these two function calls. If this event fires immediately, then an item to the incrementalChanges structure would be added, but then in the second call directly deleted, so that it will never be sent and the other peer's state would became invalid.
makeFullSync();
/* what if between these 2 calls a new change is made, that is saved in the
changes data structure, that will be deleted by deleteIncrementalChanges()?
Then this change would be lost? If I change the order it is not better ...
*/
deleteIncrementalChanges();
Some good links and, in the case the first scenario (it pauses running code) is true, solutions are welcomed.
Javascript is single threaded, and keeps an event stack of stuff it needs to get to once it's done running the current code it's working on. It will not start the next event in the stack until the current one is finished.
If you make multiple asynchronous calls, such as calls for a server to update data on another client, you need to structure your code to handle the case where they don't necessarily reach the second client in the same order.
If you're sending changes one at a time to another user, you can time stamp the changes to track what order they were made on the first client.
Do they pause code, that is already running, or do they wait until it has finished?
They wait until it has finished. JavaScript is single threaded, more than one piece of code can not run at once. JS uses an event loop to handle asynchronous stuff. If an event such as a click handler or timer firing happens while another piece of code is running, that event is queued up and runs after the currently running code finishes executing.
Assuming makeFullSync(); and deleteIncrementalChanges(); are called in the same chunk of code they will be executed one after another without any click events being processed until after they have both run.
One almost exception to the nothing runs in parallel rule in JS is WebWorkers. You can send data off to a worker for processing which will happen in another thread. Even though they run in parallel their results are inserted back into the event loop like any other event.

Delaying a setTimeout()

I'm having an issue with some asynchronous JavaScript code that fetches values from a database using ajax.
Essentially, what I'd like to do is refresh a page once a list has been populated. For that purpose, I tried inserting the following code into the function that populates the list:
var timer1;
timer1 = setTimeout([refresh function], 1000);
As you might imagine, this works fine when the list population takes less than 1 second, but causes issues when it takes longer. So I had the idea of inserting this code into the function called on the success of each ajax call:
clearTimeout(timer1);
timer1 = setTimeout([refresh function], 1000);
So in theory, every time a list element is fetched the timer should reset, meaning that the refresh function should only ever be called 1 second after the final list element is successfully retrieved. However, in execution all that happens is that timer1 is reset once, the first time the second block of code is reached.
Can anybody see what the problem might be? Or if there's a better way of doing this? Thanks.
==========
EDIT: To clear up how my ajax calls work: one of the issues with the code's structure is that the ajax calls are actually nested; the callback method of the original ajax call is itself another ajax call, whose callback method contains a database transaction (incorrect - see below). In addition, I have two such methods running simultaneously. What I need is a way to ensure that ALL calls at all levels have completed before refreshing the page. This is why I thought that giving both methods one timer, and resetting it every time one of the callback methods was called, would keep pushing its execution back until all threads were complete.
Quite honestly, the code is very involved-- around 140 lines including auxiliary methods-- and I don't think that posting it here is feasible. Sorry-- if no one can help without code, then perhaps I'll bite the bullet and try copying it here in a format that makes some kind of sense.
==========
EDIT2: Here's a general workflow of what the methods are trying to do. The function is a 'synchronisation' function, one that both sends data to and retrieves data from the server.
I. Function is called which retrieves items from the local database
i. Every time an item is fetched, it is sent to the server (ajax)
a. When the ajax calls back, the item is updated locally to reflect
its success/failure
II. A (separate) list of items is retrieved from the local database
i. Every time an item is fetched, an item matching that item's ID is fetched from the server (ajax)
a. On successful fetch from server, the items are compared
b. If the server-side item is more recent, the local item is updated
So the places I inserted the second code block above are in the 'i.' sections of each method, in other words, where the ajax should be calling back (repeatedly). I realize that I was in error in my comments above; there is actually never a nested ajax call, but rather a database transaction inside an ajax call inside a database transaction.
You're doing pretty well so far. The trick you want to use is to chain your events together, something like this:
function refresh()
{
invokeMyAjaxCall(param1, param2, param3, onSuccessCallback, onFailureCallback);
}
function onSuccessCallback()
{
// Update my objects here
// Once all the objects have been updated, trigger another ajax call
setTimeout(refresh, 1000);
}
function onFailureCallback()
{
// Notify the user that something failed
// Once you've dealt with the failures, trigger another call in 1 sec
setTimeout(refresh, 1000);
}
Now, the difficulty with this is: what happens if a call fails? Ideally, it sounds like you want to ensure that you are continually updating information from the server, and even if a temporary failure occurs you want to keep going.
I've assumed here that your AJAX library permits you to do a failure callback. However, I've seen some cases when libraries hang without either failing or succeeding. If necessary, you may need to use a separate set of logic to determine if the connection with the server has been interrupted and restart your callback sequence.
EDIT: I suspect that the problem you've got is a result of queueing the next call before the first call is done. Basically, you're setting up a race condition: can the first call finish before the next call is triggered? It may work most times, or it may work once, or it may work nearly all the time; but unless the setTimeout() is the very last statement in your "response-processing" code, this kind of race condition will always be a potential problem.

Intercepting browser slow script messages

Is is possible to intercept browser messages such as:
Firefox:
A script on this page may be busy, or
it may have stopped responding. You
can stop the script now, open the
script in the debugger, or let the
script continue.
I.E.
A script on this page is causing your
web browser to run slowly. If it
continues to run, your computer might
become unresponsive.
These messages are occuring due to the page having alot of javascript/jquery activity.
I appricate that the fact the these messages are appearing in the first place indicate a wider problem, but is there a way of intercerping this message/situation on the client side so that a more user friendly message can be shown?
No there's no way to do this, imagine a malicious user writing a script which slows down your browser until is completely unusable, now the "Slow Script" Warning may come to the rescue, but what if he could intercept it and prevent it from being shown?
You'll need to find a solution for the underlying problem, that is, in case that you're doing a lot of calculations(which I suppose you do), you need to split those of into chunks, put them into a queue and process them either asynchronously(if possible) or in order, but with a small timeout in between.
In pseudo code it may look like this:
var queue = []; // put your functions or the data in here
function() processQueue{
if (queue.length > 0) {
var item = queue.shift() // pop of the first item of the queue
item(); // call the function, or in case of data pass it to th processing function
setTimeout(processQueue, 100); // wait 100 ms before processing the next chunck
}
}
setTimeout(processQueue, 0);
No, there is no way to intercept these messages, they are are there at a lower level in the engine to protect the user. Instead look at what's taking so long, optimize as much as possible...possibly breaking your work up into chunks that have gaps in processing so you don't trigger the messages.

Any issue with setTimeout calling itself?

I have read a handful of setTimeout questions and none appear to relate to the question I have in mind. I know I could use setInterval() but it is not my prefered option.
I have a web app that could in theory be running a day or more without a page refresh and more than one check a minute. Am I likely to get tripped up if my function calls itself several hundred (or more) times using setInterval? Will I reach "stack overflow" for example?
If I use setInterval there is a remote possibility of two requests being run at the same time especially on slow connections (where a second one is raised before the first is finished). I know I could create flags to test if a request is already active, but I'm afraid of false positives.
My solution is to have a function call my jquery ajax code, do its thing, and then as part of ajaxComplete, it does a setInterval to call itself again in X seconds. This method also allows me to alter the duration between calls, so if my server is busy(slow), one reply can set a flag to increase the time between ajax calls.
Sample code of my idea...
function ServiceOrderSync()
{
// 1. Sync stage changes from client with the server
// 2. Sync new orders from server to this client
$.ajax( { "data": dataurl,
"success": function(data)
{ // process my data },
"complete": function(data)
{
// Queue the next sync
setTimeout( ServiceOrderSync, 15000 );
});
}
You won't get a stack overflow, since the call isn't truly recursive (I call it "pseudo-recursive")
JavaScript is an event driven language, and when you call setTimeout it just queues an event in the list of pending events, and code execution then just continues from where you are and the call stack gets completely unwound before the next event is pulled from that list.
p.s. I'd strongly recommend using Promises if you're using jQuery to handle async code.

Categories

Resources