這是一篇繼event loop和MicroTask 后的vue.nextTick API實現(xiàn)的源碼解析。
預(yù)熱,寫一個sleep函數(shù)
function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms)}async function oneTick (ms) { console.log('start') await sleep(ms) console.log('end')}oneTick(3000)解釋下sleep函數(shù)
async 函數(shù)進行await PromiseFn()時函數(shù)執(zhí)行是暫停的,我們也知道現(xiàn)在這個PromiseFn是在microTask內(nèi)執(zhí)行。當microTask沒執(zhí)行完畢時,后面的macroTask是不會執(zhí)行的,我們也就通過microTask在event loop的特性實現(xiàn)了一個sleep函數(shù),阻止了console.log的執(zhí)行
流程
1執(zhí)行console.log('start')
2執(zhí)行await 執(zhí)行暫停,等待await函數(shù)后的PromiseFn在microTask執(zhí)行完畢
3在sleep函數(shù)內(nèi),延遲ms返回
4返回resolve后執(zhí)行console.log('end')
nextTick API
vue中nextTick的使用方法
vue.nextTick(() => { // todo...})了解用法后看一下源碼
const nextTick = (function () { const callbacks = [] let pending = false let timerFunc // 定時函數(shù) function nextTickHandler () { pending = false const copies = callbacks.slice(0) // 復(fù)制 callbacks.length = 0 // 清空 for (let i = 0; i < copies.length; i++) { copies[i]() // 逐個執(zhí)行 } } if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // 重點 } } else if ('!isIE MutationObserver') { var counter = 1 var observer = new MutationObserver(nextTickHandler) // 重點 var textNode = document.createTextNode(string(conter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { timerFunc = () => { setTimeout(nextTickHandler, 0) // 重點 } } return function queueNextTick (cb, ctx) { // api的使用方式 let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { err } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve =resolve }) } }})() // 自執(zhí)行函數(shù)大致看一下源碼可以了解到nextTick api是一個自執(zhí)行函數(shù)
既然是自執(zhí)行函數(shù),直接看它的return類型,return function queueNextTick (cb, ctx) {...}
return function queueNextTick (cb, ctx) { // api的使用方式 let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { err } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve =resolve }) } }
新聞熱點
疑難解答
圖片精選