国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

淺談Vue.nextTick 的實現方法

來源:懂視網 責編:小采 時間:2020-11-27 22:27:06
文檔

淺談Vue.nextTick 的實現方法

淺談Vue.nextTick 的實現方法:這是一篇繼event loop和MicroTask 后的vue.nextTick API實現的源碼解析。 預熱,寫一個sleep函數 function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) } async function oneT
推薦度:
導讀淺談Vue.nextTick 的實現方法:這是一篇繼event loop和MicroTask 后的vue.nextTick API實現的源碼解析。 預熱,寫一個sleep函數 function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) } async function oneT

這是一篇繼event loop和MicroTask 后的vue.nextTick API實現的源碼解析。

預熱,寫一個sleep函數

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函數

async 函數進行await PromiseFn()時函數執行是暫停的,我們也知道現在這個PromiseFn是在microTask內執行。當microTask沒執行完畢時,后面的macroTask是不會執行的,我們也就通過microTask在event loop的特性實現了一個sleep函數,阻止了console.log的執行

流程

1執行console.log('start')
2執行await 執行暫停,等待await函數后的PromiseFn在microTask執行完畢
3在sleep函數內,延遲ms返回
4返回resolve后執行console.log('end')

nextTick API

vue中nextTick的使用方法

vue.nextTick(() => {
 // todo...
})

了解用法后看一下源碼

const nextTick = (function () {
 const callbacks = []
 let pending = false
 let timerFunc // 定時函數

 function nextTickHandler () {
 pending = false
 const copies = callbacks.slice(0) // 復制
 callbacks.length = 0 // 清空
 for (let i = 0; i < copies.length; i++) {
 copies[i]() // 逐個執行
 }
 }

 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
 })
 }
 }
})() // 自執行函數

大致看一下源碼可以了解到nextTick api是一個自執行函數

既然是自執行函數,直接看它的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
 })
 }
 }

只關注主流程queueNextTick函數把我們傳入的() => { // todo... } 推入了callbacks內

 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) // 重點
 }
 }

這一段我們可以看到標注的三個點表明在不同瀏覽器環境下使用Promise, MutationObserver或setTimeout(fn, 0) 來執行nextTickHandler

function nextTickHandler () {
 pending = false
 const copies = callbacks.slice(0) // 復制
 callbacks.length = 0 // 清空
 for (let i = 0; i < copies.length; i++) {
 copies[i]() // 逐個執行
 }
 }

nextTickHandler就是把我們之前放入callbacks的 () => { // todo... } 在當前tasks內執行。

寫一個簡單的nextTick

源碼可能比較繞,我們自己寫一段簡單的nextTick

const simpleNextTick = (function () {
 let callbacks = []
 let timerFunc

 return function queueNextTick (cb) {
 callbacks.push(() => { // 給callbacks 推入cb()
 cb()
 })

 timerFunc = () => {
 return Promise.resolve().then(() => {
 const fn = callbacks.shift()
 fn()
 })
 }
 timerFunc() // 執行timerFunc,返回到是一個Promise
 }
})()

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

我們可以從這里看出nextTick的原理就是返回出一個Promise,而我們todo的代碼在這個Promise中執行,現在我們還可以繼續簡化

const simpleNextTick = (function () {
 return function queueNextTick (cb) {
 timerFunc = () => {
 return Promise.resolve().then(() => {
 cb()
 })
 }
 timerFunc()
 }
})()

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

直接寫成這樣。

const simpleNextTick = function queueNextTick (cb) {
 timerFunc = () => {
 return Promise.resolve().then(() => {
 cb()
 })
 }
 timerFunc()
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

這次我們把自執行函數也簡化掉

const simpleNextTick = function queueNextTick (cb) {
 return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

現在我們直接簡化到最后,現在發現nextTick最核心的內容就是Promise,一個microtask。

現在我們回到vue的nextTick API官方示例

<div id="example">{{message}}</div>
var vm = new Vue({
 el: '#example',
 data: {
 message: '123'
 }
})
vm.message = 'new message' // 更改數據
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
 vm.$el.textContent === 'new message' // true
})

原來在vue內數據的更新后dom更新是要在下一個事件循環后執行的。
nextTick的使用原則主要就是解決單一事件更新數據后立即操作dom的場景。

既然我們知道了nextTick核心是利用microTasks,那么我們把簡化過的nextTick和開頭的sleep函數對照一下。

const simpleNextTick = function queueNextTick (cb) {
 return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick') // 也可以換成ajax請求
})
function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms) // 也可以換成ajax請求
}
async function oneTick (ms) {
 console.log('start')
 await sleep(ms)
 console.log('end')
}
oneTick(3000)

我們看出nextTick和我么寫的oneTick的執行結果是那么的相似。區別只在于nextTick是把callback包裹一個Promise返回并執行,而oneTick是用await執行一個Promise函數,而這個Promise有自己包裹的webapi函數。

那在用ajax請求的時候我們是不是直接這樣使用axios可以返回Promise的庫

async function getData () {
 const data = await axios.get(url)
 // 操作data的數據來改變dom
 return data
}

這樣也可以達到同nextTick同樣的作用

最后我們也可以從源碼中看出,當瀏覽器環境不支持Promise時可以使用MutationObserver或setTimeout(cb, 0) 來達到同樣的效果。但最終的核心是microTask

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

淺談Vue.nextTick 的實現方法

淺談Vue.nextTick 的實現方法:這是一篇繼event loop和MicroTask 后的vue.nextTick API實現的源碼解析。 預熱,寫一個sleep函數 function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) } async function oneT
推薦度:
標簽: VUE 實現 方式
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 天码毛片一区二区三区入口 | 欧美另类网站 | 欧美整片第一页 | 欧美日韩一区二区在线观看 | 日本一区二区三区免费看 | 欧美亚洲国产日韩一区二区三区 | 亚洲人成一区 | 亚洲 欧洲 另类 综合 自拍 | 国产区在线观看 | 国产成人精品视频在放 | 久久综合中文字幕一区二区 | 精品国产免费一区二区三区五区 | 国产成人乱码一区二区三区在线 | 欧美 日韩 国产在线 | 欧美精品亚洲精品日韩专区va | 欧美成a人片在线观看 | 91po国产在线精品免费观看 | 全网毛片免费 | 久久伊人精品一区二区三区 | 99精品国产免费久久国语 | 成人美女黄网站色大色费 | 国产福利久久青青草原下载 | 日韩在线资源 | 日本中文字幕有码 | 欧美日韩成人高清色视频 | 欧美日韩精品一区二区 | 一级毛片免费毛片一级毛片免费 | 国产精品亚洲高清一区二区 | 欧美视频精品一区二区三区 | 欧美日韩精品一区二区 | 国产成人手机在线好好热 | 欧美在线视频观看 | 久久久精品一区二区三区 | 欧美人与性动交a欧美精品 欧美日本一道本 | 亚洲 欧洲 另类 综合 自拍 | 亚洲欧美在线视频观看 | 国产欧美日韩在线不卡第一页 | 99久久国产亚洲综合精品 | 精品国产一区二区三区久久影院 | 亚洲欧美日韩综合在线 | 中文字幕亚洲天堂 |