Why are some JavaScript developers using setTimeou

2019-01-18 04:16发布

问题:

This question already has an answer here:

  • Why is setTimeout(fn, 0) sometimes useful? 17 answers

I have problem when using jQuery plugin tablesorter and I can't call trigger twice.

For example this won't work:

this._$table.trigger('update');
this._$table.trigger('sorton', [[[1,1]]]);

But this works:

this._$table.trigger('update');
setTimeout($.proxy(function() {
    this._$table.trigger('sorton', [[[1,1]]]);
}, this), 1);

And then I see that problem was in trigger 'update', it call method with body:

function () {
    var me = this;
    setTimeout(function () {
        // rebuild parsers.
        me.config.parsers = buildParserCache(
        me, $headers);
        // rebuild the cache map
        cache = buildCache(me);
    }, 1);
}

Why did the tablesorter developer use setTimeout with one millisecond?

回答1:

It's an old hack. If an event needs to be triggered after another event you can use setTimeout with 1ms to make sure the event is triggered after the other event.



回答2:

Short asnwer: Function execution queueing

This is the short answer to your question. setTimeout with either 0 or 1 millisecond is used for function execution queueing. Read on to find out why and how.

Javascript has single threaded execution

Javascript engine is a single threaded process. So whenever developers wanted to defer some function execution to get executed right after the current one that's just being executed, a setTimeout is being used to actually queue the next function... It doesn't have anything to do directly with events although functions may be event handlers. The only event in this equation is the timeout event that setTimeout creates.

This is an example of two functions where the first function during its execution queues a second function to be executed right after it.

function first()
{
    // does whatever it needs to

    // something else needs to be executed right afterwards
    setTimeout(second, 1);

    // do some final processing and exit
    return;
}

function second()
{
    // whatever needs to be done
}

So to javascript engine thread the execution queue looks like this:

first()
second()

Mind that this has nothing to do with function call stack.

Why 1ms?

1ms is a very short amount of time, which (almost) assures that your second function will get executed right after your first function returns. You may see sometimes even 0ms which actually executes it right after first function returns.

If one would on the other hand use longer time i.e. 100ms this could result in a different function getting executed in the meantime and that could have an undesired effect on the whole UI process.

Why function queueing in the first place?

Browsers nowadays prevent client side functionality to hang current browser session by observing long running functions. If a particular function runs long enough, browser Javascript execution engine will pause it and ask the user whether they want to terminate it (kill it) or wait for it to complete.

This is usually undesired effect when you actually do have a long running function. For instance imagine you have a function that has to loop through a large number of items processing each one during the process. You definitely don't want the user to terminate the process because the loop needs to execute.

What's the solution in this case? In such case instead of having a single function with loop and executing it, you'd rather have the loop (queueing) function that would then queue function calls for processing each item. This is just an outer skeleton of such functionality.

function queueItems(items) {
    for(var i = 0; i < items.length, i++)
    {
        setTimeout((function(item) {
            return function() {
                processItem(item);
            };
        })(items[i]), 0);
    }
}

function processItem(item) {
    // process individual item
}

This way you'd prevent your functions to run too long and after each executed function control would get back to Javascript engine resetting its function-hang timer. But be aware that while your functions are being executed your UI will likely be unresponsive or at most unpredictable. It may be better to queue your function with some time space in between so UI stays responsive if that's desired.



回答3:

I think that since trigger('update') internally has a setTimeout, only by setting another setTimeout you can achieve the desired order of statement execution. If you don't call 'sorton' through setTimeout it will be executed before 'update'.

On the other hand I guess 'update' uses setTimeout for preventing 'update' from being a blocking function when it may take a long time to be executed.