JavaScript函数和UI更新
我有一个下面的函数,它将相对定位的元素1000px从现在的位置滑出JavaScript函数和UI更新,javascript,settimeout,Javascript,Settimeout,我有一个下面的函数,它将相对定位的元素1000px从现在的位置滑出 for (var i = 0; i < 1000; i++) { $('.my-element').css( 'left', parseInt($('.my-element').css('left'), 10) + 1 ); } for(变量i=0;i
for (var i = 0; i < 1000; i++) {
$('.my-element').css(
'left',
parseInt($('.my-element').css('left'), 10) + 1
);
}
for(变量i=0;i<1000;i++){
$('.my元素').css(
"左",,
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);
}
for(变量i=0;i<1000;i++){
setTimeout(函数(){
$('.my元素').css(
"左",,
parseInt($('.my element').css('left'),10)+1
);
}, 0);
}
这会产生元素向右滑动1000px的视觉效果
现在,根据我的理解和这个SO线程,UI更新在浏览器事件队列中排队,就像异步回调像setTimeout回调一样排队一样
因此,在第一种情况下,基本上,在执行for循环时,会生成一个包含1000个UI更新的队列
在第二种情况下,首先创建一个包含1000个setTimeout回调的队列,该队列在执行时创建另一个包含1000个UI更新的队列
因此,最终,这两种情况都会创建相同的1000个UI更新队列。那么为什么视觉效果会有差异呢
我必须在这里查看一些重要的JavaScipt和浏览器渲染概念。任何能启发我的人都将不胜感激
注意:以上示例纯粹是为了理解目的,而不是试图创建一个JS函数来滑动DOM元素。这可能是最好的思考方法。浏览器可以做两件事之一。它要么运行javascript,要么呈现webapge,两者都不能 这是因为javascript代码是100%阻塞的,这意味着在浏览器执行所有阻塞代码之前,它永远不会放弃控制 第一个示例只包含块代码,因此浏览器永远不会有机会渲染,直到元素已经到达需要的位置 您的第二个示例包含使用setTimeout(延迟阻塞代码)的阻塞代码,该代码将一组阻塞代码排队,以便稍后(在所有其他阻塞代码完成后)由浏览器自行决定(在其呈现和javascript运行周期之间)执行 因此,第二个例子是循环将完全执行,将1000个函数排队在某个时间点执行,但尽可能接近0毫秒。现在阻塞代码已经完成了一个或多个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);
setTimeout(函数(){//这使得页面加载并放置一秒钟
var delay=100,//动画之间的延迟
距离=25,//移动的总距离
sync=false;//应该使用阻塞代码吗
如果(同步){
var i=0,
时间=0,
last=新日期();
while(i=延迟){
move(i++);
已用-=延迟;
}
}
}否则{
对于(变量i=0;i
您可以更改延迟
、距离
和同步
变量。两个循环都等待在每个动画之间移动元素delay
毫秒。它们都将把一个div总共移动距离
像素。但是,其中一个(setTimeout)将有一个可见的动画,而另一个将只是拍摄。如果您使同步方法的延迟或距离过长,则实际上会冻结浏览器,同步解决方案将不会有此问题
Logan肯定回答了您的问题,但我建议您研究一下滑动效果,而不是循环。试想一下,for循环的每一次迭代都在穿越DOM,寻找一类
的所有元素。my element
-几乎没有效率!此示例纯粹是为了理解浏览器如何执行JavaScript和更新UI。不是尝试创建滑动功能。但是,如果UI更新排队到浏览器事件队列,则第一个示例将添加到队列1000 UI更新,其中浏览器必须为每个队列项目在不同位置绘制元素。(因此,我认为会产生滑动视觉效果)在第二个示例中,1000个排队的setTimeout回调必须在setTimeout回调结束时创建1000个UI更新,我认为这与第一个示例相同。@Prashant第一个示例中似乎没有队列。脚本将元素的左CSS属性更改1000次。当浏览器开始呈现页面时,它只看到最终结果。仅仅更改CSS属性本身不会触发重画。好的,这意味着链接线程上的这个注释是误导性的。因为在没有setTimeout的示例中,他提到将UI更新添加到队列中。他甚至还提到,在JS函数结束时,元素的重新绘制速度非常快,即使发生了三次不同的UI更新,似乎只有最后一次更新是可见的。因此,我添加了代码,显示无论延迟如何,由于执行阻塞javascript代码,您在渲染时总会遇到延迟。您可以遵循JSFIDLE链接并处理变量