摘要:盡量把所有異步代碼放在一個(gè)宏微任務(wù)中,減少消耗加快異步代碼的執(zhí)行。我們知道,如果一個(gè)異步代碼就注冊(cè)一個(gè)宏微任務(wù)的話,那么執(zhí)行完全部異步代碼肯定慢很多避免頻繁地更新。中就算我們一次性修改多次數(shù)據(jù),頁(yè)面還是只會(huì)更新一次。
寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟
專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】
如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧
【Vue原理】NextTick - 源碼版 之 獨(dú)立自身
好的,今天到了 nextTick 的環(huán)節(jié),之前我看的版本是 2.5.17,然后瞄了一眼 2.6 的,發(fā)現(xiàn)對(duì)于 nextTick 修改了 少部分內(nèi)容,但是不太大,所以就一起記錄下來(lái)
(如果改太多,就懶得看了.....反正了解一個(gè)思想以及實(shí)現(xiàn)思路就行了)
nextTick 是一個(gè)在 Vue 中比較獨(dú)立的東西,可以直接拿出來(lái)為你的項(xiàng)目服務(wù)
nextTick 涉及的點(diǎn),就下面這些
1、任務(wù)隊(duì)列callbacks 2、任務(wù)隊(duì)列執(zhí)行函數(shù) flushCallbacks 3、控制(宏任務(wù),微任務(wù))注冊(cè)標(biāo)志位 pending 4、宏任務(wù),微任務(wù)
沒(méi)看懂?沒(méi)關(guān)系,后面會(huì)慢慢說(shuō)
這篇先講 nextTick 自身,下篇再講 nextTick 和 Vue 的關(guān)聯(lián)
接下來(lái)就是一個(gè)個(gè)去詳細(xì)記錄了
宏任務(wù),微任務(wù)這個(gè)知識(shí)點(diǎn),很重要,也不算太簡(jiǎn)單,在網(wǎng)上也能找到很多很好的講解,比如下面這篇文章,在這里不會(huì)特別解釋這兩個(gè),畢竟主題不是這個(gè)
https://juejin.im/post/59e85e...
宏微任務(wù)的下面總結(jié)也是個(gè)人理解,有錯(cuò)盡管罵我
那么這里就先記錄一下相關(guān)的結(jié)論
1、宏任務(wù)和微任務(wù)都是異步 2、宏任務(wù)和微任務(wù)會(huì)被注冊(cè)到兩個(gè)不同的隊(duì)列中 3、宏任務(wù)隊(duì)列不是一次性清空?qǐng)?zhí)行,而是執(zhí)行一個(gè)宏任務(wù)時(shí), 然后去清空?qǐng)?zhí)行一列微任務(wù)隊(duì)列
接著再執(zhí)行下一個(gè)宏任務(wù).....循環(huán)往復(fù),直到所有隊(duì)列都為空
什么是一個(gè)宏任務(wù)比如 一個(gè) setTimeout 就是一個(gè)宏任務(wù),兩個(gè) setTimeout 就是兩個(gè)宏任務(wù)
例子說(shuō)明執(zhí)行順序比如現(xiàn)在,宏任務(wù)隊(duì)列中有兩個(gè) setTimeout,微任務(wù)隊(duì)列中有兩個(gè) Promise
假設(shè)現(xiàn)在正在執(zhí)行第一個(gè)宏任務(wù) setTimeout,執(zhí)行完之后,會(huì)開(kāi)始清空?qǐng)?zhí)行 微任務(wù)隊(duì)列
于是開(kāi)始執(zhí)行了兩個(gè)Promise
結(jié)束之后,接著執(zhí)行 另一個(gè)宏任務(wù), setTimeout
以前我以為是 宏任務(wù)隊(duì)列執(zhí)行完,再執(zhí)行微任務(wù)隊(duì)列,發(fā)現(xiàn)不是,很受傷,都是了解 nextTick 源碼讓我有機(jī)會(huì)重新了解了一遍 這個(gè)知識(shí)點(diǎn)
常見(jiàn)宏任務(wù)setTimeout
setInterval
setImmediate
script
MessageChannel
常見(jiàn)微任務(wù)Promise
MutationObserver
Object.observe(廢棄)
process.nextTick(node)
Vue 中的宏任務(wù) 和 微任務(wù) 源碼以下談的是 版本 2.5.17 的,在 2.6 中,去掉宏任務(wù)了
在這里先埋下兩個(gè)問(wèn)題
1、Vue為什么需要宏任務(wù)和 微任務(wù) 2、Vue在哪里使用到了宏任務(wù)和微任務(wù)
這兩個(gè)問(wèn)題會(huì)記錄在另外一篇文章
Vue 中有兩個(gè)函數(shù),macroTimerFunc 用于注冊(cè)宏任務(wù),microTimerFunc 用于注冊(cè)微任務(wù)
以適用于不同的場(chǎng)景,下面就是這兩個(gè)函數(shù)的源碼
1、macroTimerFuncif(如果setImmediate存在) { macroTimerFunc =function(){ setImmediate(flushCallbacks); }; } elseif(如果MessageChannel存在) { varchannel =newMessageChannel(); varport = channel.port2; channel.port1.onmessage = flushCallbacks; macroTimerFunc =function(){ port.postMessage(1); }; } else{ macroTimerFunc =function(){ setTimeout(flushCallbacks,0); }; }
沒(méi)啥好說(shuō)的,最多記錄一下 MessageChannel,更多內(nèi)容就自己查啦
MessageChannel
簡(jiǎn)單來(lái)說(shuō),MessageChannel 用于創(chuàng)建了一個(gè)通信的管道,這個(gè)管道有兩個(gè)端口
每個(gè)端口都可以通過(guò)postMessage發(fā)送數(shù)據(jù)
一個(gè)端口綁定onmessage回調(diào),從另一個(gè)端口接收傳過(guò)來(lái)的數(shù)據(jù)
不多說(shuō)了,看下一個(gè)微任務(wù)
2、microTimerFuncif(如果promise存在) { varp =Promise.resolve(); microTimerFunc =function(){ p.then(flushCallbacks); }; }else{ microTimerFunc = macroTimerFunc; }
上面的宏微任務(wù) 函數(shù)都 出現(xiàn)了一個(gè) flushCallbacks 的東西,下面會(huì)有
Vue 的任務(wù)隊(duì)列vue 自己維護(hù)了一個(gè)任務(wù)隊(duì)列去配合 宏微任務(wù)使用,目的無(wú)非是幾樣
1、減少宏微任務(wù)的注冊(cè)。盡量把所有異步代碼放在一個(gè) 宏微任務(wù)中,減少消耗
2、加快異步代碼的執(zhí)行。我們知道,如果一個(gè)異步代碼就注冊(cè)一個(gè)宏微任務(wù)的話,那么執(zhí)行完全部異步代碼肯定慢很多
3、避免頻繁地更新。Vue 中就算我們一次性修改多次數(shù)據(jù),頁(yè)面還是只會(huì)更新一次。就是因?yàn)檫@樣,避免多次修改數(shù)據(jù)導(dǎo)致的多次頻繁更新頁(yè)面,讓多次修改只用更新最后一次
下面就來(lái)說(shuō)一下Vue 相關(guān)的實(shí)現(xiàn)
1、callbackscallbacks 是一個(gè)數(shù)組,用于存放各種異步函數(shù)。比如
this.$nextTick(()=>{ console.log(1111) })
就會(huì)把你設(shè)置的這個(gè)回調(diào),放到 callbacks 數(shù)組中
callbacks.push(()=>{ console.log(1111) })
既然 callbacks 是存放異步回調(diào)的,那么肯定有一個(gè)方法,是遍歷 callbacks ,然后逐個(gè)執(zhí)行其中存放的函數(shù)
沒(méi)錯(cuò),這個(gè)方法就是 flushCallbacks
2、flushCallbacks方法灰常簡(jiǎn)單啊,大家肯定能看得懂啊
1、復(fù)制一遍 callbacks
2、把 原來(lái) callbacks 清空
3、遍歷 復(fù)制的 callbacks ,然后逐個(gè)執(zhí)行
var callbacks = []; var pending =false; functionflushCallbacks(){ pending =false; varcopies = callbacks.slice(0); callbacks.length =0; for(vari =0; i < copies.length; i++) { copies[i](); } }
這個(gè)方法是 直接傳給 上面設(shè)置的 宏任務(wù)函數(shù) 和 微任務(wù)函數(shù)的額
也就是說(shuō),宏任務(wù)和 微任務(wù) 的回調(diào),都是執(zhí)行這個(gè) flushCallbacks
setTimeout(flushCallbacks)
嘿,我們之前有講過(guò),Vue 會(huì)控制當(dāng)時(shí)執(zhí)行棧的所有異步代碼只注冊(cè)一個(gè) 宏微任務(wù)
那么是怎么控制的呢?
還有還有,是怎么把 異步函數(shù) 存放到 callbacks 中的呢?
下面就需要請(qǐng)出我們的豬腳,nextTick 函數(shù)閃亮登場(chǎng)!?。?/p>
3、NextTickVue.nextTick =function(cb, ctx){ callbacks.push(function(){ cb && cb.call(ctx); }); if(!pending) { pending =true; if(useMacroTask) { macroTimerFunc(); }else{ microTimerFunc(); } } }
通過(guò)判斷 pending 來(lái)確定是否需要注冊(cè)宏微任務(wù)
當(dāng)?shù)谝淮巫?cè)的時(shí)候,把 pending 設(shè)置為 true,表示任務(wù)隊(duì)列已經(jīng)在開(kāi)始了,同一時(shí)期內(nèi)無(wú)需注冊(cè)了
然后在 任務(wù)隊(duì)列 執(zhí)行完畢之后,再把 pending 設(shè)置為 false(在 flushCallbacks 中)
你可以看到,就是在這里進(jìn)行存放 異步函數(shù),還特地【包裝】了一遍,為了綁定一個(gè)上下文對(duì)象
Vue 怎么控制注冊(cè)宏任務(wù)還是微任務(wù)呢?
沒(méi)錯(cuò),就是這個(gè)鬼東西了,設(shè)置為 true 時(shí)注冊(cè)宏任務(wù),設(shè)置為false 注冊(cè)微任務(wù)
“在 2.6 版本中,已經(jīng)不存在這個(gè)鬼東西,全部使用了微任務(wù)注冊(cè)”
在 注冊(cè) DOM 事件的時(shí)候用到,當(dāng)事件回調(diào)執(zhí)行的過(guò)程中,所有的異步代碼都使用宏任務(wù)
你問(wèn)為什么??jī)?nèi)容太多,會(huì)有專(zhuān)篇分析
然后,關(guān)于 macroTimerFunc 和 microTimerFunc 上文已經(jīng)講過(guò)啦,可以回去看看
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/110260.html
寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】NextTick - 源碼版 之 服務(wù)Vue 初次看的兄弟可以先看 【Vue原理】NextTick - 白話版 簡(jiǎn)單了解下...
摘要:這么講,有點(diǎn)籠統(tǒng),準(zhǔn)確地說(shuō),應(yīng)該是事件回調(diào)執(zhí)行過(guò)程中,在主線程為空之后,異步代碼執(zhí)行之前,所有通過(guò)注冊(cè)的異步代碼都是用宏任務(wù)。 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【...
摘要:通常會(huì)做很多判斷來(lái)選擇存在的類(lèi)型,比如判斷等是否存在,而選擇他為微任務(wù)類(lèi)型但是可能宏微任務(wù)最后都是,因?yàn)樗潜J丶嫒萏幚怼? 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專(zhuān)注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【V...
摘要:的回調(diào)函數(shù)執(zhí)行的優(yōu)先級(jí)要高于,屬于觀察者。的回調(diào)函數(shù)保存在一個(gè)數(shù)組中,會(huì)將異步回調(diào)放到當(dāng)前幀的末尾回調(diào)之前,如果過(guò)多,會(huì)導(dǎo)致回調(diào)不斷延后最后堆積太多。 阿里一面是電話面,問(wèn)得不多,但是挺有深度。面試官一開(kāi)始就說(shuō),看了你的項(xiàng)目,覺(jué)得你基礎(chǔ)挺好的,那我就不問(wèn)基礎(chǔ)了。然后全程就真的沒(méi)有問(wèn)一個(gè)基礎(chǔ)問(wèn)題。。 1.說(shuō)說(shuō)你做的那個(gè)網(wǎng)頁(yè)版手機(jī)QQ項(xiàng)目的難點(diǎn)。 我首先想到了滾動(dòng)條位置無(wú)法還原的問(wèn)題,也就...
摘要:哪吒別人的看法都是狗屁,你是誰(shuí)只有你自己說(shuō)了才算,這是爹教我的道理。哪吒去他個(gè)鳥(niǎo)命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰(shuí)和你做朋友太乙真人人是否能夠改變命運(yùn),我不曉得。我只曉得,不認(rèn)命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...
閱讀 991·2021-09-22 15:17
閱讀 1993·2021-09-22 15:06
閱讀 2292·2021-09-08 09:35
閱讀 5231·2021-09-01 11:43
閱讀 3561·2019-08-30 15:55
閱讀 2210·2019-08-30 12:48
閱讀 3235·2019-08-30 12:45
閱讀 1829·2019-08-29 17:31