Pra*_*ant 3 javascript settimeout
我有一个跟随功能,它将相对定位的元素1000px从它现在的位置滑下.
for (var i = 0; i < 1000; i++) {
$('.my-element').css(
'left',
parseInt($('.my-element').css('left'), 10) + 1
);
}
Run Code Online (Sandbox Code Playgroud)
这不会产生滑动效果.相反,在执行结束时,元素突然向右移动1000px.
现在,如果我在setTimeout中包装UI更新,如下所示:
for (var i = 0; i < 1000; i++) {
setTimeout(function () {
$('.my-element').css(
'left',
parseInt($('.my-element').css('left'), 10) + 1
);
}, 0);
}
Run Code Online (Sandbox Code Playgroud)
这会产生元素向右滑动1000px的视觉效果.
现在,根据我的不足和这个SO线程,为什么setTimeout(fn,0)有时会有用?,UI更新在浏览器事件队列中排队,就像同步回调像setTimeout回调一样排队.
因此,在第一种情况下,基本上,当执行for循环时,会产生1000个UI更新的队列.
在第二种情况下,首先,创建一个1000个setTimeout回调的队列,在执行时创建另一个1000 UI更新的队列.
因此,最终,两种情况都会创建1000个UI更新的相同队列.那为什么视觉效果不同呢?
我必须在这里查看一些重要的JavaScipt和浏览器呈现概念.任何能够启发我的人都会非常感激.
注意:上面的示例纯粹是为了理解目的,而不是尝试创建一个JS函数来滑动DOM元素.
这可能是考虑它的最佳方式.浏览器可以执行以下两种操作之一.要么运行你的javascript,要么渲染webapge,它不能同时执行这两个操作.
这是因为javascript代码是100%阻塞,这意味着在浏览器执行所有阻止代码之前它永远不会放弃控制.
您的第一个示例仅包含阻塞代码,因此在元素已经存在之前,浏览器永远不会有机会进行渲染.
您的第二个示例包含使用setTimeout(延迟阻止代码)的阻止代码,该代码将浏览器自行决定(在其rending和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);
Run Code Online (Sandbox Code Playgroud)
你可以改变的delay,distance和sync变量.两个循环都等待delay在每个动画之间移动元素毫秒.它们都会移动一个div总共distance像素.然而,一个(setTimeout)将具有可见动画而另一个将刚刚拍摄.如果您使同步方法的延迟或距离太长,您实际上将冻结浏览器,则assync解决方案将不会出现此问题!
http://jsfiddle.net/j79s4o4w/3/