<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答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
        主站蜘蛛池模板: 深夜久久AAAAA级毛片免费看| 亚洲七久久之综合七久久| 永久免费无码网站在线观看个| 午夜精品在线免费观看| 亚洲色大成网站www永久男同| 国产一卡2卡3卡4卡2021免费观看 国产一卡2卡3卡4卡无卡免费视频 | 亚洲一区免费观看| 国产99视频精品免费专区| 亚洲AV无码成人精品区在线观看 | 成年黄网站色大免费全看| 亚洲乱码无限2021芒果| 成人无码区免费视频观看| 亚洲av最新在线观看网址| 国产一级特黄高清免费大片| 大片免费观看92在线视频线视频| 4338×亚洲全国最大色成网站| 国产无限免费观看黄网站| 亚洲人成影院在线| a级毛片无码免费真人| 免费福利资源站在线视频| 亚洲精品无码成人片久久 | 午夜一级免费视频| 美女被爆羞羞网站免费| 亚洲精品无码成人AAA片| 国产精品成人观看视频免费| 久久亚洲AV成人无码国产最大| 亚洲成A人片在线观看中文| 国产免费无码一区二区 | 亚洲综合精品香蕉久久网| 99re6在线视频精品免费下载| 中中文字幕亚洲无线码| 亚洲美女高清一区二区三区| 一级毛片免费观看不卡的| 亚洲av永久无码天堂网| 久久亚洲精品视频| 永久免费看bbb| 国产婷婷成人久久Av免费高清 | 精品久久久久久无码免费 | 粉色视频成年免费人15次| 亚洲AV无码日韩AV无码导航| 日韩一区二区a片免费观看 |