前言:
前几周在研究Vue的源码,感觉设计得还是蛮精巧的。这里主要谈谈其异步更新的机制,及实现nextTick的几种方式,接着会扩展一些浏览器的event-loop的实现机制。
目录:
nextTick 与异步渲染UI
vue中,data的改变是同步的,reactive的,但ui的渲染是异步,正如nextTick 一样,都是在下一个tick去执行。
这篇文章讲得比较细,但可能用的是老版本的vue了,只涉及到了MutationObserver 和 setTimeout。
Vue nextTick 源码解读
这里的vue版本是2.5.17-beta.0。大致有以下几个要点:
- flushCallbacks 用来清空回调队列和依次执行回调。
- 定义了两个timerFunc, microTimerFunc用于执行微任务microtasks,macroTimerFunc 用于执行任务tasks。
- 放弃了MutationObserver,用setImmediate -> setImmdiate的polyfill MessageChannel -> setTimeout(fn, 0) 来构造 macroTimerFunc
- 用 Promise.resolve().then(flushCallbacks) 来构造microTimerFunc, 若没有原生支持的Promise, 则microTimerFunc 退化为 macroTimerFunc
- 默认使用 microtask 但暴露了强制使用task 的方法,如v-on绑定的事件handler
- nextTick中接受一个cb 函数,和一个上下文对象ctx,主要做了两件事
- 把cb压入回调队列
- 如果没有正在执行任务(任务队列是空的),则使用 macroTimerFunc()/ microTimerFunc() 执行flushCallbacks 清空队列。
附源代码:core/util/next-tick.js
/* @flow */
/* globals MessageChannel */
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIOS, isNative } from './env'
const callbacks = []
let pending = false
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (