JavaScript function and UI updates

I have a following function which slides a relatively positioned element 1000px off of where it is now.

for (var i = 0; i < 1000; i++) {
    $('.my-element').css(
        'left',
        parseInt($('.my-element').css('left'), 10) + 1
    );
}

This does not produces a sliding effect. Rather, by the end of the execution, the element moves abruptly 1000px to its right.

Now, if I wrap the UI updates in setTimeout like below:

for (var i = 0; i < 1000; i++) {
    setTimeout(function () {
        $('.my-element').css(
            'left',
            parseInt($('.my-element').css('left'), 10) + 1
        );
    }, 0);
}

This produces the visual effect of the element sliding 1000px to its right.

Now, according to my understaning and this SO thread, Why is setTimeout(fn, 0) sometimes useful?, UI updates are queued in the browser event queue in the same way async callbacks are queued like setTimeout callback.

So, in case first, basically, a queue of 1000 UI updates are made when the for loop is executed.

And in case second, first, a queue of 1000 setTimeout callbacks is created, which on execution, creates another queue of 1000 UI updates.

So, eventually, both cases create the same queue of 1000 UI updates. Then why the difference in the visual result?

I must be looking over some important JavaScipt and browser rendering concept here. Anyone who can enlighten me will be much appreciated.

Note: Above examples are purely for understanding purpose and not an attempt to create a JS function to slide a DOM element.


This is probably the best way to think about it. The browser can do one of two things. Either it runs your javascript or it renders the webapge, it cannot do both.

This is because javascript code is 100% blocking, meaning it will never give up control until the browser has executed all blocking code.

You first example contains only blocking code so the browser is never given the opportunity to render until the element is already where it needs to be.

Your second example contains blocking code that uses setTimeout (delayed blocking code) which queues a bunch of blocking code to be executed later (after all other blocking code has completed) at the browsers discretion (between its rending and javascript running cycles).

So the second example the loop will completely execute, queuing 1000 functions to execute at some point in time but as close to 0ms as possible. Now that the blocking code has completed one or more setTimeout may execute or the browser may render, its pretty random what actually happens though. But it will weave back and forth between rendering and executing javascript.

Take this code for example.

setTimeout(function () { //this makes it so the page loads and sits for a second
    var delay = 100, //delay between animations
        distance = 25, //total distance moved
        sync = false; //should this use blocking code

    if (sync) {
        var i = 0,
            elapsed = 0,
            last = new Date();
        while (i < distance) {
            var now = new Date();
            elapsed += (now - last);
            last = now;
            if (elapsed >= delay) {
                move(i++);
                elapsed -= delay;
            }
        }
    } else {
        for (var i = 0; i < distance; i++) {
            assyncMove(i, delay * i);
        }
    }

    function assyncMove(position, delay) {
        setTimeout(function () {
            move(position);
        }, delay);
    }

    function move(position) {
        $("div").css("left", position);
    }
}, 1000);

You can change the delay , distance , and sync variables. Both loops wait to move the element delay milliseconds between each animation. They will both move a div a total of distance pixels. However one (setTimeout) will have a visible animation while the other will just shoot over. If you make the delay or distance too long for the sync method you will actually freeze the browser, the assync solution will not have that issue!

http://jsfiddle.net/j79s4o4w/3/

链接地址: http://www.djcxy.com/p/74992.html

上一篇: 重置Javascript中for循环中同一个定时器的超时时间

下一篇: JavaScript功能和UI更新