这篇文章学习 jake 一次分享,首先感谢 jake 的分享,当然我们都是学习别人,但是我个人并不是简单地传递或翻译他人内容,而是融入了自己思想,可能是不对的,将一些自己学过过程中的遇到问题给大家分享,以便大家更好地理解作者分享的内容。
看到下面的代码,大家可能会有顾虑这样写,el 会不会在屏幕上有一闪而过的效果
我通过代码进行尝试,并没有您顾虑那种情况,因为在 javascript 中并没 race condition 的问题
在 web 页面有一个主线程,之所以叫主线程,是因为加载文件(css 或 javascript)、以及 javascript 的运行和页面渲染,dom 所有这些一切都是发生在这个线程中。
这样就表示以上所有动作都是有一定顺序,因为他们都发生一个线程里。我们无法用同时编辑和修改一个 DOM ,所以也就不存在 race condition 的问题了。但是如何某一个动作占用主线程时间过长,所谓长时间一般在 200 毫秒以上,这样就会影响其他动作,在这段时间内阻止用户交互,造成不好的用户体验。
但是我们一些耗时例如网络请求,也些用户操作、解码和编码,这些都会运行在主线程以外的线程,当结束后会将信息返回到主线程。这就是今天主题 the event loop,这里我就不翻译这个词,保持原滋原味吧。
setTimeout(callback,ms) 想必大家都用过吧,参数位置看起来有点别扭,不过今天我们抛开这个,探究一下方法背后究竟发生了什么。
当然我们不想让这个方法占据主线程那么多时间,所以我们这个方法是并行于主线运行的
但是如果并行运行的话,那么我们希望 callback 方法是返回到主线程进行执行的。但是问题来了这些异步操作当他们返回主线程对 dom 进行操作,会不会引起 race condition 呢?
为了解决这个问题,引入了任务队列,这些任务会有序地返回到主线程进行执行,
当你点击鼠标,那么如何从系统操作来到 javascript 呢?这也是进入任务队列
任务队列
任务队列是 event loop 一部分,也是历史悠久了。下图我们通过图形的形式来生动地展示 event loop 是如何工作的。
我们发现了这里有一个小门,当有任务时候小门就会开启,然后去执行任务。让浏览器通知 event loop ,hey 我们有些任务要做,就会开启小门
下面我们创建两个 setTimeout 指定相同延时时间然后进行打印来看效果
当执行这两个方法会并行于主线程进行执行,然后回到主线,执行顺序是根据任务队列顺序决定。
浏览器通知 event loop 有任务要回到主线程执行, 我有两个任务在任务队列中,这样 event loop 会按顺序依次执行两个任务
渲染步骤
这是浏览是如何更新屏幕输出的,分步渲染是 event loop 另一个小门,这里首先查询计算所有 css 然后将其应用到每一个元素上。
然后(Layout)是布局,根据渲染树(dom 的结构)来放置每个元素到屏幕上其该有的位置。
最后也就是根据样式和位置信息生产 pixel 数据,每一个像素的颜色以及透明度,然后根据这些数据进行绘制。
如果我们点击这个按钮,整个 JavaScript 世界就停止在您点击这一刻,无法进行任何操作。
为什么会这样呢?当您点击按钮,浏览器通知 event loop 这一个任务需要你执行,event loop 就会立即执行任务,
不过这是无限任务,几毫秒后浏览器还想让 event loop 去做一些其他类似更新界面工作。
不过这是 event loop 没有完成手头上工作是无法进行下一项工作的。
回到开始问题,我们担心会有闪烁效果,不过事实证明并没有闪烁效果,这是因为这些代码是在浏览器进行下一个阶段分步渲染前已经被执行完毕了。event loop 会确保在进行下一次渲染前结束任务。
当循环阻塞了渲染,那么我们将loop放置到 setTimeout 中,然后在 setTimeout 继续执行 loop 以达到循环效果。
这样再次点击按钮就不会阻塞渲染了,我们依旧可以与浏览器进行交互操作。
这样每一次执行完任务后就回到 event loop 执行渲染,
然后再去执行 loop 生产的下一个任务。
网友评论