nextTick的使用背景
在vue項目中,經常會使用到nextTick這個api,一直在猜想其是怎么實現的,今天有幸研讀了下,雖然源碼又些許問題,但仍值得借鑒
核心源碼解析
判斷當前環境使用最合適的API并保存函數
promise
判斷是否支持promise,如果支持就使用Promise對象的then方法包裹要執行的 flushCallbacks函數
MutationObserver
判斷是否支持MutationObserver,如果支持就創建一個MutationObserver 用于監聽dom改動之后執行 flushCallbacks 函數 并賦值給 observer
setImmediate
判斷是否支持setImmediate,如果支持就使用setImmediate包裹 flushCallbacks函數
setTimeout
如果以上三種都不支持使用setTimeout包裹 flushCallbacks函數
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 timerFuncif ( typeof Promise !== 'undefined' && isNative ( Promise) ) { const p = Promise. resolve ( ) timerFunc = ( ) => { p. then ( flushCallbacks) if ( isIOS) setTimeout ( noop) } isUsingMicroTask = true
} else if ( ! isIE && typeof MutationObserver !== 'undefined' && ( isNative ( MutationObserver) || MutationObserver. toString ( ) === '[object MutationObserverConstructor]'
) ) {
let counter = 1 const observer = new MutationObserver ( flushCallbacks) const textNode = document. createTextNode ( String ( counter) ) observer. observe ( textNode, { characterData : true } ) timerFunc = ( ) => { counter = ( counter + 1 ) % 2 textNode. data = String ( counter) } isUsingMicroTask = true
} else if ( typeof setImmediate !== 'undefined' && isNative ( setImmediate) ) {
timerFunc = ( ) => { setImmediate ( flushCallbacks) }
} else {
timerFunc = ( ) => { setTimeout ( flushCallbacks, 0 ) }
}
調用異步函數執行回調對列
入參分析
nextTick(cb?: Function, ctx?: Object) {}
cb是 傳入的回調函數 ctx是函數執行的上下文 而者都又是可選參數, 但是有問題 下文有解析
函數執行邏輯
將調用nextTick是傳入的執行函數添加到 callbacks中 可使用call和傳入的ctx修改傳入的執行函數的this指向
export function nextTick ( cb? : Function, ctx? : Object ) { let _resolvecallbacks. push ( ( ) => { if ( cb) { try { cb . call ( ctx) } catch ( e) { handleError ( e, ctx, 'nextTick' ) } } } ) if ( ! pending) { pending = true timerFunc ( ) }
}
這個代碼有刪減,因為其余代碼不會執行是 偽代碼 下文有解析
偽代碼分析
nexttick的參數中cb不能為可選參數,如果cb參數不傳將沒有回調函數,nextTick將沒有意義,并且ctx將成為第一個參數,由于是形參,ctx將頂替cb但是ctx不是函數類型,就會拋錯
依次執行nextTick
function flushCallbacks ( ) { pending = false const copies = callbacks. slice ( 0 ) callbacks. length = 0 for ( let i = 0 ; i < copies. length; i++ ) { copies[ i] ( ) }
}
源碼
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
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 timerFuncif ( typeof Promise !== 'undefined' && isNative ( Promise) ) { const p = Promise. resolve ( ) timerFunc = ( ) => { p. then ( flushCallbacks) if ( isIOS) setTimeout ( noop) } isUsingMicroTask = true
} else if ( ! isIE && typeof MutationObserver !== 'undefined' && ( isNative ( MutationObserver) || MutationObserver. toString ( ) === '[object MutationObserverConstructor]'
) ) {
let counter = 1 const observer = new MutationObserver ( flushCallbacks) const textNode = document. createTextNode ( String ( counter) ) observer. observe ( textNode, { characterData : true } ) timerFunc = ( ) => { counter = ( counter + 1 ) % 2 textNode. data = String ( counter) } isUsingMicroTask = true
} else if ( typeof setImmediate !== 'undefined' && isNative ( setImmediate) ) {
timerFunc = ( ) => { setImmediate ( flushCallbacks) }
} else {
timerFunc = ( ) => { setTimeout ( flushCallbacks, 0 ) }
} export function nextTick ( cb? : Function, ctx? : Object ) { let _resolvecallbacks. push ( ( ) => { if ( cb) { try { cb . call ( ctx) } catch ( e) { handleError ( e, ctx, 'nextTick' ) } } else if ( _resolve) { console. log ( 'ctx' ) _resolve ( ctx) } } ) if ( ! pending) { pending = true timerFunc ( ) } if ( ! cb && typeof Promise !== 'undefined' ) { return new Promise ( resolve => { _resolve = resolve} ) }
}
個人困惑
本人實在是不太理解下列代碼的意義是什么,感覺是沒用的,但是不太確定,以下是個人分析
分析
首先將執行上下文this拋出是沒什么意義的 其次promise的resolve 單獨拿出來在此處有什么作用呢
let _resolveif ( ! cb && typeof Promise !== 'undefined' ) { return new Promise ( resolve => { _resolve = resolve} ) } _resolve ( ctx)
致謝
感謝您百忙之中抽時間閱讀我寫的博客,謝謝你的肯定,也希望對您能有所幫助 如果您有更好的見解請在評論區留言或者私聊我,期待與您的交流