代码顺序:vue
一、Vue实例初始化android
二、renderMixin中设置$nextTickAPIgit
三、nextTick源码github
如下为nextTick源码的注释(这里只将源码中的注释删掉了,加了中文注释)web
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
// noop 为空函数
// handleError 为错误处理
// isIE 为判断是否为IE环境
// isIOS 为判断是否为iOS环境
// isNative 为判断传入参数是否为内置函数
// 是否使用微任务标志(默认为false)
export let isUsingMicroTask = false
const callbacks = []
let pending = false
// 清空执行回调
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0) // 全部的回调函数浅拷贝
callbacks.length = 0 // 清空回调函数队列
for (let i = 0; i < copies.length; i++) {
copies[i]() // 依次执行回调函数
}
}
// 清空回调队列方法
let timerFunc
// 优先判断Promise是否存在(非undefined & 必须为内置函数)
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve() // 初始化一个Promise对象(fulfilled)
timerFunc = () => {
p.then(flushCallbacks)
// iOS中在一些异常的webview中,promise结束后任务队列并无刷新
// 因此强制执行setTimeout刷新任务队列
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true // 重置使用微任务标示为true
} else if (
!isIE &&
typeof MutationObserver !== 'undefined' &&
(
isNative(MutationObserver) ||
MutationObserver.toString() === '[object MutationObserverConstructor]'
)
) {
// 在android、iOS、PhantomJS使用MutationObserver
// MutationObserver接口提供了监视对DOM树所作更改的能力
// 参考地址:https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
let counter = 1
// 实例化新的MutationObserver对象
// 在实例化的时候传入flushCallbacks为变化时回调
// MutationObserver回调为微任务!
const observer = new MutationObserver(flushCallbacks)
// 建立一个文本节点
const textNode = document.createTextNode(String(counter))
// 对建立的文本节点监听
// 参考地址:https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver/observe
observer.observe(textNode, {
characterData: true // 在文本节点变化时,记录更新前的值
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter) // 更新文本节点内容
}
isUsingMicroTask = true // 重置使用微任务标示为true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
// 使用setImmediate(只有IE支持,宏任务可是优先级比setTimeout高)
// 参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setImmediate
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
// 上述方案均不可行时使用setTimeout方法
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
// 对外暴露的nextTick方法
export function nextTick (cb?: Function, ctx?: Object) {
// cb为用户传入的回调函数
// ctx为当前vue实例(this)
let _resolve
// 在回调队列中加入回调函数
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx) // 执行回调函数并绑定this
} catch (e) {
handleError(e, ctx, 'nextTick') // 异常处理
}
} else if (_resolve) {
// 若是cb无效且_resolve已经置为promise.resolve
// 则执行一次
_resolve(ctx)
}
})
if (!pending) {
// 将pending置为true并开始执行回调队列
pending = true
timerFunc()
}
// 当cb不存在时,将_resolve置为promise.resolve
// 并返回promise对象
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
复制代码