代碼順序: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
})
}
}
複製代碼