可以抽象为事件循环的简单代码表示for(macroTaskofmacroTaskQueue){//1.处理当前MACRO-TASKhandleMacroTask();//2.为(microTaskQueue的microTask)处理所有MICRO-TASK{handleMicroTask(microTask);}}js事件机制JavaScript是一种单线程语言,一次只能执行一个任务。对于javascript事件处理机制,我们可以简单理解为“主线程+任务队列”模式。主要步骤如下(1)所有同步任务都在主线程上执行,形成一个执行栈。(2)除了主线程之外,还有一个“任务队列”。一旦异步任务有运行结果,就会在“任务队列”中放入一个事件。(3)一旦“ExecutionStack”中的所有同步任务都执行完毕,系统会读取“TaskQueue”,看看里面有什么事件。那些对应的异步任务结束等待状态,进入执行栈,开始执行。(4)主线程不断重复上面的第三步。任务队列任务队列分为任务队列和微任务队列。清空执行栈任务后,会先从Microtasks中取出任务,待Microtasks执行完毕后,再执行任务中的任务。因此,一个事件循环的主要流程是:启动一个事件循环执行栈,从任务队列中取出任务并执行。执行完成后,清除执行栈。从微任务队列中获取执行堆栈并执行完成。清除执行堆栈以确定微任务队列中是否有任何任务。如果有任何任务,请重复步骤3。进入Updatetherendering(更新渲染)阶段,事件循环结束流程图如下:仔细理解开头列出的代码:for(macroTaskofmacroTaskQueue){//1.处理当前MACRO-TASKhandleMacroTask();//2.为(microTaskQueue的microTask)处理所有MICRO-TASK{handleMicroTask(microTask);}}为什么VUE和EVENT_LOOP使用Microtask队列对于VUE这样的web2.0框架来说,最重要的是将数据的修改映射到DOM上。如果只修改一条数据,DOM刷新一次,那么在一个同步过程中,同时修改几条数据,势必会导致多次渲染。这绝对不可取。从上面的事件循环我们知道,一个事件循环对应一个render。当然,理想情况是最好在渲染事件循环生成的所有更改之前更新DOM。这样一个循环只能渲染一次。从这个需求出发,不难发现微任务队列是满足需求的。微任务队列必须在渲染ui之前执行。与多个任务队列的存在不同,微任务只有一个队列。最重要的是:microtask队列只有全部清空才能进入下一步,不管什么时候塞进队列。在实际代码中,无论是鼠标点击、键盘输入还是网络时间,触发了哪些方法,这些触发都可以看成是开启了一个事件循环。这些trigger引起的任何修改都放在microtask队列中,保证了这一轮evnet循环到达renderui时,可以获取到最新的DOM。需要注意的是,这里的render并不维护虚拟DOM,也不会将虚拟DOM的变化投射到真实DOM上。相反,它是将真实DOM更新到UI的过程。这是因为:EventLoop没有在ECMAScript标准中定义,而是在HTML标准中定义:协调事件、用户交互、脚本、渲染、网络等......在JavaScript引擎中(以V8为例),它只是实现了ECMAScript标准,并不关心事件循环。也就是说,Eve??ntLoop属于JavaScriptRuntime,由宿主环境(如浏览器)提供。浏览器不关心虚拟DOM。只负责在DOM变化后渲染UI。为什么不使用和上面一样的任务队列:在启动一个事件循环后,如果将任务放入任务队列,那么只有在本轮事件循环结束后才会执行任务任务,新一轮的事件循环将启动。这无疑会导致UI被渲染两次。其实游达曾经为了修复一些bug,用任务队列实现了VUE.nexttick。但它造成了明显的性能问题。可以看两个例子:例1和例2。两个fiddle的实现是完全一样的,就是让绝对定位的黄色元素起到固定定位的效果:绑定scroll事件,计算当前每次滚动时滚动值。position并更改为该绝对定位元素的top属性。自己滚动几下,对比一下效果,你会发现第一个fiddle中的黄色元素稳定固定很好。然后最后fiddle出问题了,黄色元素上下晃动,好像跟不上我们滚动的节奏,肯定是慢了点,虽然停止滚动的时候位置是正确的结尾。以上两个例子其实都是在这个issue中找到的。第一个jsfiddle使用的版本是Vue2.0.0-rc.6。该版本的nextTick实现使用了MO,由于IOS9.3的WebView中的MO存在bug,所以游鱼溪将实现改为window.postMessage,也就是使用的Vue2.0.0-rc.7后一个小提琴。后来尤雨溪才知道,window.postMessage就是放callback的macrotask队列。这就是问题的根源。参考:Tasks,microtasks,queuesandschedules深入理解JavaScriptEventLoopVue源码详解nextTick:MutationObserver只是浮云,microtask才是核心!
