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)
致谢
感谢您百忙之中抽时间阅读我写的博客,谢谢你的肯定,也希望对您能有所帮助 如果您有更好的见解请在评论区留言或者私聊我,期待与您的交流