JavaScript 函数和 UI 更新

JavaScript function and UI updates

本文关键字:更新 UI 函数 JavaScript      更新时间:2023-09-26

>我有一个以下函数,可以将相对位置的元素从现在的位置滑出1000px。

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

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

现在,如果我将 UI 更新包装在 setTimeout 中,如下所示:

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和浏览器渲染概念。任何能启发我的人都会不胜感激。

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

这可能是最好的思考方式。浏览器可以执行以下两项操作之一。它要么运行你的javascript,要么渲染webapge,它不能同时做这两件事。

这是因为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毫秒。它们都将移动一个div 总共 distance 像素。但是,一个(setTimeout(将具有可见的动画,而另一个将刚刚拍摄。如果您使同步方法的延迟或距离太长,您实际上会冻结浏览器,assync 解决方案不会有这个问题!

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