【Vue原理】NextTick - 源碼版 之 獨立自身

寫文章不容易,點個讚唄兄弟 專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧 研究基於 Vue版本 【2.5.17】vue

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧node

【Vue原理】NextTick - 源碼版 之 獨立自身 數組

好的,今天到了 nextTick 的環節,以前我看的版本是 2.5.17,而後瞄了一眼 2.6 的,發現對於 nextTick 修改了 少部份內容,可是不太大,因此就一塊兒記錄下來promise

(若是改太多,就懶得看了.....反正瞭解一個思想以及實現思路就好了)bash

nextTick 是一個在 Vue 中比較獨立的東西,能夠直接拿出來爲你的項目服務異步

nextTick 涉及的點,就下面這些函數

一、任務隊列callbacks
二、任務隊列執行函數 flushCallbacks
三、控制(宏任務,微任務)註冊標誌位 pending
四、宏任務,微任務
複製代碼

沒看懂?不要緊,後面會慢慢說post

這篇先講 nextTick 自身,下篇再講 nextTick 和 Vue 的關聯學習

接下來就是一個個去詳細記錄了ui


宏任務,微任務

這個知識點,很重要,也不算太簡單,在網上也能找到不少很好的講解,好比下面這篇文章,在這裏不會特別解釋這兩個,畢竟主題不是這個

juejin.im/post/59e85e…

宏微任務的下面總結也是我的理解,有錯儘管罵我

公衆號

那麼這裏就先記錄一下相關的結論

一、宏任務和微任務都是異步
二、宏任務和微任務會被註冊到兩個不一樣的隊列中
三、宏任務隊列不是一次性清空執行,而是執行一個宏任務時,
而後去清空執行一列微任務隊列
複製代碼

接着再執行下一個宏任務.....循環往復,直到全部隊列都爲空

什麼是一個宏任務

好比 一個 setTimeout 就是一個宏任務,兩個 setTimeout 就是兩個宏任務

例子說明執行順序

好比如今,宏任務隊列中有兩個 setTimeout,微任務隊列中有兩個 Promise

假設如今正在執行第一個宏任務 setTimeout,執行完以後,會開始清空執行 微任務隊列

因而開始執行了兩個Promise

結束以後,接着執行 另外一個宏任務, setTimeout

之前我覺得是 宏任務隊列執行完,再執行微任務隊列,發現不是,很受傷,都是瞭解 nextTick 源碼讓我有機會從新瞭解了一遍 這個知識點

常見宏任務

setTimeout

setInterval

setImmediate

script

MessageChannel

常見微任務

Promise

MutationObserver

Object.observe(廢棄)

process.nextTick(node)


Vue 中的宏任務 和 微任務 源碼

如下談的是 版本 2.5.17 的,在 2.6 中,去掉宏任務了

在這裏先埋下兩個問題

一、Vue爲何須要宏任務和 微任務
二、Vue在哪裏使用到了宏任務和微任務
複製代碼

這兩個問題會記錄在另一篇文章

Vue 中有兩個函數,macroTimerFunc 用於註冊宏任務,microTimerFunc 用於註冊微任務

以適用於不一樣的場景,下面就是這兩個函數的源碼

一、macroTimerFunc

if(若是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);
    };
}
複製代碼

沒啥好說的,最多記錄一下 MessageChannel,更多內容就本身查啦

MessageChannel

簡單來講,MessageChannel 用於建立了一個通訊的管道,這個管道有兩個端口

每一個端口均可以經過postMessage發送數據

一個端口綁定onmessage回調,從另外一個端口接收傳過來的數據

很少說了,看下一個微任務

二、microTimerFunc

if(若是promise存在) {    

    varp =Promise.resolve();

   microTimerFunc =function(){
        p.then(flushCallbacks);
    };
}else{
    microTimerFunc = macroTimerFunc;
}
複製代碼

上面的宏微任務 函數都 出現了一個 flushCallbacks 的東西,下面會有


Vue 的任務隊列

vue 本身維護了一個任務隊列去配合 宏微任務使用,目的無非是幾樣

一、減小宏微任務的註冊。儘可能把全部異步代碼放在一個 宏微任務中,減小消耗

二、加快異步代碼的執行。咱們知道,若是一個異步代碼就註冊一個宏微任務的話,那麼執行徹底部異步代碼確定慢不少

三、避免頻繁地更新。Vue 中就算咱們一次性修改屢次數據,頁面仍是隻會更新一次。就是由於這樣,避免屢次修改數據致使的屢次頻繁更新頁面,讓屢次修改只用更新最後一次

下面就來講一下Vue 相關的實現

一、callbacks

callbacks 是一個數組,用於存放各類異步函數。好比

this.$nextTick(()=>{    

    console.log(1111)

})
複製代碼

就會把你設置的這個回調,放到 callbacks 數組中

callbacks.push(()=>{    
    console.log(1111)
})
複製代碼

既然 callbacks 是存放異步回調的,那麼確定有一個方法,是遍歷 callbacks ,而後逐個執行其中存放的函數

沒錯,這個方法就是 flushCallbacks

二、flushCallbacks

方法灰常簡單啊,你們確定能看得懂啊

一、複製一遍 callbacks

二、把 原來 callbacks 清空

三、遍歷 複製的 callbacks ,而後逐個執行

var callbacks = [];

var pending =false;


functionflushCallbacks(){

   pending =false;    

    varcopies = callbacks.slice(0);

   callbacks.length =0;    

    for(vari =0; i < copies.length; i++) {

       copies[i]();
    }
}
複製代碼

這個方法是 直接傳給 上面設置的 宏任務函數 和 微任務函數的額

也就是說,宏任務和 微任務 的回調,都是執行這個 flushCallbacks

setTimeout(flushCallbacks)
複製代碼

嘿,咱們以前有講過,Vue 會控制當時執行棧的全部異步代碼只註冊一個 宏微任務

那麼是怎麼控制的呢?

還有還有,是怎麼把 異步函數 存放到 callbacks 中的呢?

下面就須要請出咱們的豬腳,nextTick 函數閃亮登場!!!

公衆號

三、NextTick

Vue.nextTick =function(cb, ctx){

    callbacks.push(function(){
        cb && cb.call(ctx);
   });    

    if(!pending) {

       pending =true;        

        if(useMacroTask) {

           macroTimerFunc();
        }else{
            microTimerFunc();
        }
    }
}

複製代碼
一、pending

經過判斷 pending 來肯定是否須要註冊宏微任務

當第一次註冊的時候,把 pending 設置爲 true,表示任務隊列已經在開始了,同一時期內無需註冊了

而後在 任務隊列 執行完畢以後,再把 pending 設置爲 false(在 flushCallbacks 中)

二、callbacks

你能夠看到,就是在這裏進行存放 異步函數,還特意【包裝】了一遍,爲了綁定一個上下文對象

三、useMacroTask

Vue 怎麼控制註冊宏任務仍是微任務呢?

沒錯,就是這個鬼東西了,設置爲 true 時註冊宏任務,設置爲false 註冊微任務

「在 2.6 版本中,已經不存在這個鬼東西,所有使用了微任務註冊」

這個東西,在哪裏用過啊?

在 註冊 DOM 事件的時候用到,當事件回調執行的過程當中,全部的異步代碼都使用宏任務

你問爲何?內容太多,會有專篇分析

而後,關於 macroTimerFunc 和 microTimerFunc 上文已經講過啦,能夠回去看看

公衆號
相關文章
相關標籤/搜索