前端筆記-vue v2.6.10源碼註釋-nextTick

代碼順序: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 爲判斷傳入參數是否爲內置函數

// 是否使用微任務標誌(默認爲falseexport 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
    })
  }
}

複製代碼
相關文章
相關標籤/搜索