JavaScript功能和UI更新

我有一个以下功能,将相对定位的元素从现在的位置滑出1000px。

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

这不会产生滑动效果。 相反,在执行结束时,元素突然向右移动1000px。

现在,如果我在下面的setTimeout中包装UI更新:

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

这产生了元素向右滑动1000px的视觉效果。

现在,根据我的解释和这个SO线程,为什么setTimeout(fn,0)有时候有用?,UI更新在浏览器事件队列中排队,就像同步回调排队等待setTimeout回调一样。

因此,在第一种情况下,基本上,执行for循环时将执行1000个UI更新队列。

在第二种情况下,首先创建一个包含1000个setTimeout回调的队列,并在执行时创建1000个UI更新的另一个队列。

因此,最终,这两种情况都会创建1000个UI更新的相同队列。 那么为什么视觉效果的差异呢?

我必须在这里查看一些重要的JavaScipt和浏览器渲染概念。 任何能够启发我的人都会非常感激。

注意:以上示例纯粹是为了理解目的,而不是尝试创建用于滑动DOM元素的JS函数。


这可能是考虑它的最佳方式。 浏览器可以做两件事之一。 要么它运行你的JavaScript或它呈现网页,它不能做到这一点。

这是因为JavaScript代码是100%阻止的,这意味着在浏览器执行所有阻止代码之前,它绝对不会放弃控制权。

你的第一个例子只包含了阻止代码,所以浏览器从来没有机会渲染,直到元素已经到达需要的位置。

你的第二个例子包含了使用setTimeout(延迟阻塞代码)的阻塞代码,它在浏览器的判断之间(在其延期和JavaScript运行周期之间)排队一批阻塞代码以便稍后执行(在所有其他阻塞代码完成之后)。

所以第二个例子循环将完全执行,排队1000个函数在某个时间点执行,但尽可能接近0ms。 现在阻止代码已经完成了一个或多个setTimeout可能执行或者浏览器可以渲染,但它实际上发生了什么。 但它会在呈现和执行javascript之间来回编织。

以此代码为例。

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);

您可以更改delaydistancesync变量。 两个循环等待在每个动画之间移动元素delay毫秒。 它们都会移动一个distance像素的总和。 然而,一个(setTimeout)将有一个可见的动画,而另一个只会拍摄。 如果您为同步方法延迟或延长距离,实际上会冻结浏览器,那么assync解决方案就不会有这个问题!

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

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

上一篇: JavaScript function and UI updates

下一篇: Why JavaScript declared variable is in the global object before initialization?