我不完全理解 JavaScript 线程
在我深入讨论这个问题之前。让我声明一下,通过事件循环,我指的是 http://en.wikipedia.org/wiki/Event_loop< /a>.这是浏览器实现的东西。有关更多信息,请阅读:http://javascript.info/教程/further-javascript-features/events-and-timing-deep。
这个问题又难又长,请耐心看完!我非常感谢所有的答案!
所以。现在,据我了解,在 JavaScript 中只有一个主线程(即在大多数浏览器环境中)。因此,像这样的代码:
for (var color = 0x000; color < 0xfff; color++) {
$('div').css('background-color', color.toString(16));
}
将产生从黑到白的动画,但您不会看到它,因为渲染是在处理代码后完成的(当下一个tick发生时 - 浏览器输入事件循环)。
如果你想看动画,你可以这样做:
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 调用产生的渲染事件?
Before I dive into the question. Let me state that by Event Loop I am referring to http://en.wikipedia.org/wiki/Event_loop. This is something that browsers implement. For more information, read this: http://javascript.info/tutorial/further-javascript-features/events-and-timing-depth.
This question is hard and long, so, please try to bear with it! And I do appreciate all answers!
So. Now, as I understand it, in JavaScript there is a single main thread (in most browser environments, that is). So, code like:
for (var color = 0x000; color < 0xfff; color++) {
$('div').css('background-color', color.toString(16));
}
will produce an animation from black to white, but you won't see that because the rendering is done after the code has been processed (when the next tick happens -- the browser enters the Event Loop).
If you want to see the animation, you could do:
for (var color = 0x000; color < 0xfff; color++) {
setTimeout(function() {
$('div').css('background-color', color.toString(16));
}, 0);
}
The above example would produce a visible animation, because setTimeout pushes a new event to the browser Event Loop stack which will be processed after there is nothing running (it enters the Event Loop to see what to do next).
It seems that the browser in this case have 0xfff (4095) events pushed into the stack, where each of them are processed with a render process in between them. So, my first question (#1) is that when exactly does the rendering take place? Does it always take place in between the processing of two events in the Event Loop stack?
The second question is about the code in the javascript.info website link I gave you.
...
function func() {
timer = setTimeout(func, 0)
div.style.backgroundColor = '#'+i.toString(16)
if (i++ == 0xFFFFFF) stop()
}
timer = setTimeout(func, 0)
....
My question here is that will the browser push a new "rendering" event to the Event Loop stack every time it reaches the div.style. ... = ...
line? But does it not first push an event due to the setTimeout-call? So, does the browser end up in a stack like:
setTimeout event
render event
Since the setTimeout call was processed before the div style change? If that's how the stack looks like, then I would assume the next time the browser enters the Event Loop it will process the setTimeout's callback and end up having:
rendering event
setTimeout event
rendering event
and continue with the rendering event that the earlier setTimeout call produced?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问1:不一定。浏览器不同程度地实现了优化。例如,他们可能会等待收集多个样式更改,然后再触发昂贵的布局重新计算。所以答案是:取决于具体的浏览器。
试试这个:http://taligarsiel.com/Projects/howbrowserswork1.htm#Render_tree_construction (该文档的日期为 2009 年 10 月 - 即它是足够最新的)
Q2:渲染不一定与 JS 执行相同 - 这是两个不同的引擎。 JS 引擎不负责渲染,它只是与渲染引擎交互。在我看来,第二个问题的主要信息是JS 与渲染引擎的独立性。请记住,浏览器(或网页)不需要 Javascript,它们的主要目的是基于 CSS 样式规则呈现 HTML。 JavaScript 只是操作 HTML(实际上是 DOM 树)和样式规则的一种方法。
请注意,您可以通过读取样式定义来强制渲染 - 此时渲染引擎别无选择,只能处理任何未完成的样式更改,特别是当它涉及任何位置更改时。这就是为什么在进行大量样式更改或添加大量元素之前,应该从渲染树中删除对象(例如,通过设置显示:无 - 可见性:隐藏是不够的,因为元素的大小仍被考虑用于布局),例如当许多行被一一添加(“for”循环)到表中。
根本不是问题的一部分 - 但由于我刚刚提到了显示:无和可见性:隐藏之间的区别,这也是添加隐藏位置:绝对元素(如对话框)时要考虑的因素。虽然使用一种或另一种方法隐藏绝对定位的元素没有明显的区别,但内部存在很大的区别:当使用visibility:hidden隐藏时,该元素是渲染树的一部分,而使用display:none时,它是渲染树的一部分不是。因此,如果有这样一个需要频繁切换的元素,则应该使用visibility:hidden,因为当“显示”样式在“无”和“阻止”之间切换时,浏览器必须首先渲染它。
Q1: Not necessarily. Browsers to varying degrees implement optimizations. For example, they may wait to collect several style changes before triggering an expensive recalculation of the layout. So the answer is: depends on the specific browser.
Try this: http://taligarsiel.com/Projects/howbrowserswork1.htm#Render_tree_construction (the document is dated Oct 2009 - i.e. it is sufficiently up to date)
Q2: The rendering is not necessarily the same as the JS execution - that's two different engines. Ths JS engine is not responsible for the rendering, it just interfaces with the render engine. It seems to me the main message for your second question is this independence of the JS from the rendering engine. Remember, a browser (or a webpage) does not need Javascript, their main purpose is to render HTML based on CSS style rules. Javascript is just one way to manipulate the HTML (the DOM tree really) and the style rules.
Note that you can force rendering by reading a style definition - at this point the rendering engine has no choice but process any outstanding style changes, especially if it involves any position changes. That's why one should remove objects from the rendering tree (e.g. by setting display:none - visibility:hidden is NOT enough since the element's size is still considered for layout) before doing a lot of style changes or adding a lot of elements, e.g. when lots of rows are added one by one (a "for" loop) to a table.
Not part of the question at all - but since I just mentioned a difference between display:none and visibility:hidden, that's also a consideration when adding hidden position:absolute elements like dialogs. While there is no visible difference whether an absolutely positioned element is hidden from you using one or the other method, internally there IS a big difference: when hidden using visibility:hidden the element is part of the rendering tree, with display:none it is not. So, if one has such an element that needs to be toggled a lot one should use visibility:hidden, because when the "display" style is switched between "none" and e.g. "block" the browser has to render it first.
你提到的文章只考虑了Javascript。浏览器中还发生了很多事情;回流和重绘可以由更多的事情触发;请查看以下链接以获取更多信息。
我不会使用 setTimeout为此目的。
编辑:
根据评论,推荐的方法是使用 requestAnimationFrame。截至撰写本文时,此功能仅在大多数浏览器的不稳定版本中可用。然而,有几个 库 可提供跨浏览器访问,并在必要时回退到使用 setTimeout。
看一下这个演示,了解在旧浏览器和新浏览器中工作的示例:
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
The article you mention only considers Javascript. A lot more happens in the browser; reflowing and repainting are/can be triggered by a lot more things; take a look at the following links for more info on this.
I wouldn't use setTimeout for this purpose.
Edit:
As per the comments, the recommended way is to use requestAnimationFrame. As of this writing, this is only available in unstable releases of most browsers. There are however several libraries available providing cross-browser access to it, and fall back to using setTimeout if necessary.
Take a look at this demo for an example working in old browsers, as well as in new ones:
http://paulirish.com/2011/requestanimationframe-for-smart-animating/