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的基 ...
随机推荐
- 阶段3 2.Spring_01.Spring框架简介_01.spring课程四天安排
spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...
- H5、原生app、混合开发三者比较
一.概念 a) H5:即Html5,接触过互联网的都知道html,所以很明显h5是html的第5次重大修改的一项超文本标记语言的标准协议. b) 原生:使用原生制作APP(Native app),即在 ...
- MySQL orzdba、dodba、top、iostat、vmstat、perf等
1 mysq自带的mysqladmin命令 mysqladmin -usystem -p*** -h127.0.0.1 -P3306 -r -i 1 extended-status \ |grep & ...
- Prometheus告警模型分析
Prometheus作为时下最为流行的开源监控系统,其庞大的生态体系:包括针对各种传统应用的Exporter,完整的二次开发工具链,与Kubernetes等主流平台的高度亲和以及由此带来的强大的自发现 ...
- mysqli实现增删改查(转)
1.面向对象 在面向对象的方式中,mysqli被封装成一个类,它的构造方法如下: __construct ([ string $host [, string $username [, string $ ...
- Appium - multiprocessing.pool.MaybeEncodingError-【 “Can’t pickle local object ‘PoolManager.__init__.<locals>.<lambda>‘】
公司同事学习自动化新装环境后,run多进程测试用例时出错: multiprocessing.pool.MaybeEncodingError: Error sending result: ’<ap ...
- cmd命令简单别木马的蛛丝马迹
一些基本的Windows命令往往可以识别木马的蛛丝马迹,而且在保护网络安全上起到很大的作用. 检测网络连接 如果你怀疑自己的计算机上被别人安装了木马,或者是中了病毒,但是手里没有完善的工具来检测是不是 ...
- C# 流与文件(Stream & File & byte[])
原文:https://www.cnblogs.com/long-gengyun/archive/2010/03/28/1698681.html 文件概述 文件在操作时表现为流,即流是从一些输入中读取 ...
- [转帖]VPS、虚拟主机、云主机的区别
引用知乎网友通俗的例子解释: https://www.cnblogs.com/fjping0606/p/9993849.html 其实 应该是 vps 只是 单台物理机上面的虚拟机 云主机 可能是资源 ...
- Codeforces893F_Subtree Minimum Query
题意 给定一棵树和根,每个点有点权,强制在线询问\(x\)子树里离\(x\)距离不超过\(k\)的最小点权. 分析 权值线段树合并的套路题,dfs,以深度作为下标,点权作为值,对每个点建立一颗权值线段 ...