5

在我深入探讨这个问题之前。让我声明一下,事件循环指的是http://en.wikipedia.org/wiki/Event_loop。这是浏览器实现的。有关更多信息,请阅读:http: //javascript.info/tutorial/further-javascript-features/events-and-timing-depth

这个问题又难又长,所以请尽量忍耐!我非常感谢所有答案!


所以。现在,据我了解,在 JavaScript 中只有一个主线程(即在大多数浏览器环境中)。所以,像这样的代码:

for (var color = 0x000; color < 0xfff; color++) {
    $('div').css('background-color', color.toString(16));
}

将产生一个从黑色到白色的动画,但您不会看到,因为渲染是在处理完代码之后完成的(当下一个滴答发生时——浏览器进入事件循环)。

如果你想看动画,你可以这样做:

for (var color = 0x000; color < 0xfff; color++) {
    setTimeout(function() {
        $('div').css('background-color', color.toString(16));
    }, 0);
}

上面的例子会产生一个可见的动画,因为 setTimeout 将一个新事件推送到浏览器事件循环堆栈,它将在没有任何运行后处理(它进入事件循环以查看下一步该做什么)。

在这种情况下,浏览器似乎将 0xfff (4095) 事件推入堆栈,其中每个事件都在它们之间通过渲染过程进行处理。所以,我的第一个问题(#1)是渲染到底是什么时候发生的?它是否总是发生在事件循环堆栈中两个事件的处理之间?


第二个问题是关于我给你的 javascript.info 网站链接中的代码。

...
  function func() { 
    timer = setTimeout(func, 0)
    div.style.backgroundColor = '#'+i.toString(16)
    if (i++ == 0xFFFFFF) stop()
  }

timer = setTimeout(func, 0)
....

我的问题是浏览器是否会在每次到达div.style. ... = ...线路时将新的“渲染”事件推送到事件循环堆栈?但是由于 setTimeout 调用,它不会首先推送事件吗?那么,浏览器是否最终出现在一个堆栈中,例如:

setTimeout event
render event

由于 setTimeout 调用是在 div 样式更改之前处理的?如果这就是堆栈的样子,那么我会假设下次浏览器进入事件循环时,它将处理 setTimeout 的回调并最终得到:

rendering event
setTimeout event
rendering event

并继续之前的 setTimeout 调用产生的渲染事件?

4

2 回答 2

6

Q1:不一定。浏览器在不同程度上实现了优化。例如,他们可能会在触发昂贵的布局重新计算之前等待收集多个样式更改。所以答案是:取决于具体的浏览器。

试试这个:http ://taligarsiel.com/Projects/howbrowserswork1.htm#Render_tree_construction (文档日期为 2009 年 10 月 - 即它是最新的)

Q2:渲染不一定和JS执行一样——那是两个不同的引擎。JS 引擎不负责渲染,它只是与渲染引擎接口。在我看来,第二个问题的主要信息是JS 与渲染引擎的独立性。请记住,浏览器(或网页)不需要 Javascript,它们的主要目的是根据 CSS 样式规则呈现 HTML。Javascript 只是操纵 HTML(实际上是 DOM 树)和样式规则的一种方式。

请注意,您可以通过读取样式定义来强制渲染 - 此时渲染引擎别无选择,只能处理任何未完成的样式更改,尤其是当它涉及任何位置更改时。这就是为什么在进行大量样式更改或添加大量元素之前,应该从渲染树中删除对象(例如,通过设置 display:none - visibility:hidden 是不够的,因为元素的大小仍被考虑用于布局),例如,当许多行被一一添加(“for”循环)到表中。

根本不是问题的一部分 - 但因为我刚刚提到了 display:none 和 visibility:hidden 之间的区别,所以在添加 hidden position:absolute 元素(如对话框)时,这也是一个考虑因素。虽然使用一种或另一种方法对您隐藏绝对定位的元素没有明显的区别,但在内部存在很大的区别:当使用可见性隐藏时:隐藏元素是渲染树的一部分,使用 display:none 它是不是。因此,如果有这样一个元素需要频繁切换,则应该使用可见性:隐藏,因为当“显示”样式在“无”和“阻止”之间切换时,浏览器必须首先呈现它。

于 2011-03-05T12:28:24.287 回答
1

您提到的文章仅考虑 Javascript。浏览器中发生了更多事情;回流和重绘是/可以由更多的事情触发;查看以下链接以获取更多信息。

我不会为此目的使用 setTimeout 。

编辑: 根据评论,推荐的方法是使用 requestAnimationFrame。在撰写本文时,这仅在大多数浏览器的不稳定版本中可用。然而,有几个可用的 提供对它的跨浏览器访问,并在必要时回退到使用 setTimeout。

查看此演示,了解在旧浏览器和新浏览器中工作的示例:http: //paulirish.com/2011/requestanimationframe-for-smart-animating/

于 2011-03-05T12:32:25.063 回答