JS执行时单线程的,是基于事件循环的
所有同步任务在主线程上执行,行程一个执行栈
主线程之外,还存在一个 任务队列 。只要异步任务有了运行结果,就在 任务队列 中放置一个事件。
一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看有哪些事件,对应哪些异步任务,结束等待状态,进入执行栈,开始执行
主线程不断重复上面三步
任务类型
主线程的执行过程就是一个 tick,而所有的异步结果都是通过 “任务队列” 来调度被调度。 消息队列中存放的是一个个的任务(task)。 规范中规定 task 分为两大类,分别是 macro task 和 micro task。
在同一次事件循环内会将micro task
队列中的所有任务执行完毕,且先于macro task
。macro task
中两个不同的任务之间可能穿插着UI的重新渲染,那么我们只需要在micro task
中把所有UI渲染之前需要更新的数据全部更新,这样只需要一次重渲染就能得到最新的DOM
在浏览器环境中,常见的 macro task 有 setTimeout、MessageChannel、postMessage、setImmediate;常见的 micro task 有 MutationObsever 和 Promise.then。
Vue的实现
1 | // src/core/util/next-tick.js |
默认使用microTimerFunc
1 | // 将传入的回调放入callbacks数组中,在调用任务函数时遍历执行 |
在更改数据的时候,触发数据setter
,在setter
中调用nextTick(flushSchedulerQueue)
,所以数据更新在nextTick
的时候,DOM才会改变