event loop 与 vue
结论
对于event loop 可以抽象成一段简单的代码表示
for (macroTask of macroTaskQueue) {
// 1. Handle current MACRO-TASK
handleMacroTask();
// 2. Handle all MICRO-TASK
for (microTask of microTaskQueue) {
handleMicroTask(microTask);
}
}
js事件机制
javascript是一个单线程语言,同一时间只能执行一个任务。
对于javascript的事件处理机制,我们可以简单理解成“主线程+任务队列”模式。主要步骤如下
(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个 "任务队列"(task queue)。只要异步任务有了运行结果,就在 "任务队列" 之中放置一个事件。
(3)一旦 "执行栈" 中的所有同步任务执行完毕,系统就会读取 "任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。(4)主线程不断重复上面的第三步。
任务队列
任务队列分为task queue和microtask queue。执行栈任务清空后会先从Microtasks中取任务,Microtasks中执行完之后才会执行task中的任务。
因此一个event loop主要流程如下:
- 开始一个Event loop
- 执行栈从tasks queue中取任务,并执行。
- 执行完后,执行栈清空
- 执行栈从microtasks queue中取任务执行
- 执行完成,执行栈清空
- 判断microtasks queue是否还有任务,有则重复步骤3。
- 进入 Update the rendering(更新渲染)阶段
- Event loop结束
流程图如下:
再仔细理解一下开头列出的代码:
for (macroTask of macroTaskQueue) {
// 1. Handle current MACRO-TASK
handleMacroTask();
// 2. Handle all MICRO-TASK
for (microTask of microTaskQueue) {
handleMicroTask(microTask);
}
}
VUE与EVENT_LOOP
为什么使用Microtask queue
对于VUE这类web2.0框架而言,最主要做的应该还是把对data的修改映射到DOM上。如果只修改一个数据,就刷新一次DOM,那么在一个同步过程中,同时修改好几个数据,必然会导致多次渲染。这肯定是不可取的。
从上面的event loop我们了解到,一个event loop对应一次render。理想状况当然就是,一次event loop产生的所有改动最好再render之前将DOM都先更新好。这样在一个周期中就可以只render一次。
从这点需求出发很容易发现,microtask queue很符合要求。
- microtask queue肯定在render ui之前执行完
- 不像task queue存在多个,microtask只存在一个queue。
- 最关键的是: microtask queue只有都清空了才能进入下一步,无论queue里是什么时候塞进来的。
实际代码中,不管是鼠标点击还是键盘输入或是网络时间,触发了哪些方法,这些触发都可以看成开启一个event loop。这些触发造成的任何修改都放到microtask queue中,就可以保证在这一轮的evnet loop走到render ui时可以拿到最新的DOM。
要说明的是,这里的render并不是维护虚拟DOM,也不是把虚拟DOM的变化投射到真实DOM上。而是将真实DOM更新到UI的过程。
这么说是因为:Event Loop 并不是在 ECMAScript 标准中定义的,而是在 HTML 标准中定义的:
To coordinate events, user interaction, scripts, rendering, networking, and so forth...
在 JavaScript Engine 中(以 V8 为例),只是实现了 ECMAScript 标准,而并不关心什么 Event Loop。也就是说 Event Loop 是属于 JavaScript Runtime 的,是由宿主环境提供的(比如浏览器)。
浏览器可不会关心什么虚拟DOM。只负责DOM改变后渲染UI。
为什么不用task queue
同上: 在开启一个event loop后,如果将任务放到task queue中,那么这个task任务只会在本轮Event loop结束后才会执行,并开启新一轮event loop。这无疑会导致两次render UI。
实际上,尤大为了修复一些bug,曾经将VUE.nexttick用task queue实现。但是导致了很明显的性能问题。
可以看看两个列子: 例一 , 例二
两个fiddle的实现一模一样,就是让那个绝对定位的黄色元素起到一个fixed定位的效果:绑定scroll事件,每次滚动的时候,计算当前滚动的位置并更改到那个绝对定位元素的top属性上去。大家自己试试滚动几下,对比下效果,你就会发现第一个fiddle中的黄元素是稳定不动的,fixed很好。而后一个fiddle中就有问题了,黄色元素上下晃动,似乎跟不上我们scroll的节奏,总要慢一点,虽然最后停下滚动时位置是对的。
上述两个例子其实是在这个issue中找到的,第一个jsfiddle使用的版本是Vue 2.0.0-rc.6,这个版本的nextTick实现是采用了MO,而后因为IOS9.3的WebView里的MO有bug,于是尤雨溪更改了实现,换成了window.postMessage,也就是后一个fiddle所使用的Vue 2.0.0-rc.7。后来尤雨溪了解到window.postMessage是将回调放入的macrotask 队列。这就是问题的根源了。
参考:
event loop 与 vue的更多相关文章
- JavaScript事件循环(Event Loop)机制
JavaScript 是单线程单并发语言 什么是单线程 主程序只有一个线程,即同一时间片断内其只能执行单个任务. 为什么选择单线程? JavaScript的主要用途是与用户互动,以及操作DOM.这决定 ...
- Event Loop浅谈
event loop 即事件循环.最初了解到js的event loop机制是通过自己对js中异步.同步的疑惑.今天聊一聊自己的理解,希望和大家一起学习. 首先,让我们看一个经典的setTimeOut的 ...
- Event Loop事件循环,GET!
JS中比较让人头疼的问题之一要算异步事件了,比如我们经常要等后台返回数据后进行dom操作,又比如我们要设置一个定时器完成特定的要求.在这些同步与异步事件里,异步事件肯定是在同步事件之后的,但是异步事件 ...
- event loop整理
宏任务和微任务 让我们从浏览器加载 script 说起,当浏览器加载完 script 之后,不考虑 script 标签的 defer 属性,script 将被立即执行.这时,我们就创建了一个宏任务. ...
- Atitit 解决Unhandled event loop exception错误的办法
Atitit 解决Unhandled event loop exception错误的办法 查看workspace/.metadata/.log org.eclipse.swt.SWTError: No ...
- javascript运行模式:并发模型 与Event Loop
看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和[朴灵评注]的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日 ...
- [译]Node.js - Event Loop
介绍 在读这篇博客之前,我强列建议先阅读我的前两篇文章: Getting Started With Node.js Node.js - Modules 在这篇文章中,我们将学习 Node.js 中的事 ...
- Eclipse经常报Unhandled event loop exception的原因
在公司的电脑上,Eclipse经常报Unhandled event loop exception 错误,非常频繁,通过搜索发现是因为电脑上安装了百度杀毒导致的.... 无语 另外 teamviewer ...
- Node.js 事件循环(Event Loop)介绍
Node.js 事件循环(Event Loop)介绍 JavaScript是一种单线程运行但又绝不会阻塞的语言,其实现非阻塞的关键是“事件循环”和“回调机制”.Node.js在JavaScript的基 ...
随机推荐
- Several ports (8005, 8080, 8009) required by Tomcat v8.5 Server at localhost are already in use.
Several ports (8005, 8080, 8009) required by Tomcat v8.5 Server at localhost are already in use. The ...
- LeetCode.1010-歌曲总长度可被60整除的对数
这是小川的第377次更新,第405篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第239题(顺位题号是1010).在歌曲列表中,第i首歌曲的持续时间为[i]秒. 返回其总 ...
- Linux 的简单命令以及在idea中配置码云
Linux 的简单命令: ls(list)功能:列出目录内容 cd(change directory)功能:切换目录 touch 1.txt 在当前目录创建一个文件1.txt clear:清除屏幕 p ...
- Python_Onlineh_Hmework(基础篇,持续更新中...)
1 递归 1.1 定义一个函数,求一个数的阶乘 def func(x): if x == 2: return 2 else: return x*func(x-1) a = func(4) print( ...
- [总集] LOJ 分块1 – 9
目录 分块9题 出题人hzw的解析 数列分块入门 1 修改:区间加 查询:单点值查询 代码 数列分块入门 2 修改:区间加 查询:区间排名 代码 数列分块入门 6 修改:单点插入 查询:单点值 代码 ...
- JavaScript学习总结(一)——闭包、对象、函数
一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...
- c语言程序命名规范:函数、变量、数组、文件名
函数: //send or recv data task void send_recv_data(void *pvParameters); //get socket error code. retur ...
- 图片水印处理-temp
/media/watermark 简要描述: 用户注册接口 应用场景:比较复杂的水印处理,如需要多次添加水印,或者水印图片本身也需要处理,如果处理相对简单,java项目可以通过dubbo接口Image ...
- pyrhon 开始 基础类型
https://repl.it/languages/python 线上编辑器 字符串不支持 减法 除法
- 11.jQuery之淡入淡出效果
知识点:fadeIn fadeOut fadeToggle fadeTo <style> div { width: 150px; height: 300px; background ...