JavaScript功能和UI更新 [英] JavaScript function and UI updates

查看:49
本文介绍了JavaScript功能和UI更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下功能,可以将相对定位的元素从当前位置滑出1000px.

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

这不会产生滑动效果.而是在执行结束时,元素突然向右移动了1000px.

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

现在,如果我将用户界面更新包装在setTimeout中,如下所示:

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

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

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

现在,根据我的理解和该SO线程,为什么setTimeout(fn,0)有时有用吗?,UI更新在浏览器事件队列中排队的方式与异步回调(例如setTimeout回调)一样排队.

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.

因此,首先,基本上,当执行for循环时,将进行1000个UI更新的队列.

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

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

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

因此,最终,这两种情况都将创建相同的队列,其中包含1000个UI更新.那为什么视觉效果会有所不同呢?

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

我必须在这里研究一些重要的JavaScipt和浏览器渲染概念.任何能启发我的人将不胜感激.

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

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

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

推荐答案

这可能是考虑它的最佳方法.浏览器可以执行以下两项操作之一.它要么运行您的Javascript,要么呈现Webapge,但不能两者都做.

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.

这是因为javascript代码是100%阻止的,这意味着在浏览器执行所有阻止代码之前,它永远不会放弃控制.

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.

您的第二个示例包含使用setTimeout(延迟的阻止代码)的阻止代码,该代码将一堆阻止代码排队等待稍后(在所有其他阻止代码完成之后)由浏览器决定(在其运行和javascript运行周期之间).

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

因此,第二个示例循环将完全执行,对1000个函数进行排队以在某个时间点执行,但应尽可能接近0ms.现在,阻塞代码已完成,一个或多个setTimeout可能会执行,或者浏览器可能会渲染,但是实际上发生的事情是相当随机的.但是它将在呈现和执行javascript之间来回编织.

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.

以该代码为例.

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

您可以更改 delay distance sync 变量.两个循环都等待在每个动画之间移动元素 delay 毫秒.它们都将div总共移动 distance 像素.但是,一个(setTimeout)将具有可见的动画,而另一个(仅用于拍摄).如果您为同步方法设置的延迟或距离太长,则实际上将冻结浏览器,异步解决方案将不会出现该问题!

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/

这篇关于JavaScript功能和UI更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆