亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

【Vue原理】NextTick - 源碼版 之 服務Vue

Acceml / 1670人閱讀

寫文章不容易,點個贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧
研究基于 Vue版本 【2.5.17】

如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧

【Vue原理】NextTick - 源碼版 之 服務Vue

初次看的兄弟可以先看 【Vue原理】NextTick - 白話版 簡單了解下NextTick

好的,今天,就來詳細記錄 Vue 和 nextTick 的那些事

nextTick 在 Vue 中,最重要的就是~~~

協(xié)助 Vue 進行更新操作!

上篇文章

NextTick-源碼版之獨立自身
提到過,nextTick 幫助 Vue 避免頻繁的更新,這里簡單提一下,

每次修改數(shù)據(jù),都會觸發(fā)數(shù)據(jù)的依賴更新

也就是說數(shù)據(jù)被修改的時候,會調用一遍【引用這個數(shù)據(jù)的實例】的更新函數(shù)

那么,按道理來說,修改3次,就應該調用3遍更新函數(shù),但是實際上只會調用一遍

比如我們使用 watch 監(jiān)聽 data(data 便收集了 watch 的 watcher,監(jiān)聽回調就是更新函數(shù))

結果就是只打印一次

至于依賴更新,可以看下面的文章

依賴更新 - 源碼版

其實,修改數(shù)據(jù)能夠只更新一次,不止是 nextTick 起了作用,Vue 也做了其他處理,比如過濾實例,清空隊列等等,下面就來說一下

一切先從【實例更新函數(shù)】開始

第一個要說的就是 watcher!每個實例都有一個 watcher,然后 watcher 保存著實例的更新函數(shù)

每個實例都會通過 new Vue 生成的,所以會有一個專屬的 watcher

更新函數(shù)被保存在 watcher.getter 上

function Vue(){
    ....
    new Watcher(vm, 實例更新函數(shù))
}



function Watcher(vm, expOrFn) {    

    this.getter = expOrFn;

};



Watcher.prototype.get = function() {  

    this.getter.call(vm, vm);

};

Watcher.prototype.update = function() {
    queueWatcher(this);
};
Watcher.prototype.run = function() {  

    this.get();

};

我們知道, Vue 的 data 是響應式的,就是通過 Object.defineProperty 設置 get 和 set

當數(shù)據(jù)被修改的時候, set 函數(shù)被觸發(fā),函數(shù)內部會通知所有的實例進行更新(就是調用每個實例的 watcher.update 方法)

具體可以看這個

響應式原理 - 白話版
依賴更新 - 源碼版

那么我們現(xiàn)在的重點就在 watcher.update 上了,看看上面的 Watcher 代碼

出現(xiàn)了一個 queueWatcher 的東西

更新隊列

速度看源碼!

var queue = [];

var has = {};

var index = 0;

var flushing = false;

var waiting= false;



function queueWatcher(watcher) {  



    var id = watcher.id;    



    // 如果是同一個 Vue 實例,就不要重復添加了

    if (has[id] == null) {                
              

        // 這個實例已經(jīng)被標記了

        has[id] = true;        



        // 如果沒有在運行,那么直接放入隊列

        if (!flushing) {

            queue.push(watcher);
        } else {            



            // if already flushing, splice the watcher based on its id

            // if already past its id, it will be run next immediately.
            var i = queue.length - 1;            



            // 跳過所有比我大的

            while (i > index && queue[i].id > watcher.id) {
                i--;
            }  

         

            // 最后放在隊列中,一個比我老的 watcher 后面

            queue.splice(i + 1, 0, watcher);
        }        



        // 在 flushSchedulerQueue 執(zhí)行之后設置為 false

        if (!waiting) {
            waiting = true;
            nextTick(flushSchedulerQueue);
        }
    }
}

先說說其中涉及的幾個變量

has

是一個對象,用來過濾watcher。

當這個watcher 已經(jīng)調用過更新函數(shù),那么就在 has 中標記這個 id

也就是,你同時間調用多次 watcher.update ,其實只有第一次調用有用,后面的都會被過濾掉

queue

一個數(shù)組,watcher 更新隊列,存放需要更新的 watcher

flushSchedulerQueue

watcher 更新隊列執(zhí)行函數(shù),下面有講到

waiting

為 true 表示已經(jīng)把 【watcher 更新隊列執(zhí)行函數(shù)】 注冊到宏微任務上了(或者說存放進 callbacks 中)。

正在等待JS棧為空后,就可以執(zhí)行更新。直到所有watcher 更新完畢,才重置為 false

flushing

為 true 表示 watcher 更新隊列正在執(zhí)行更新(就是開始遍歷 watcher 隊列,逐個調用 watcher 更新了)

直到所有watcher 更新完畢,才重置為 false

queueWatcher 源碼不算很復雜,主要做兩件事

1、處理watcher 更新隊列 queue

2、注冊 【watcher 更新隊列 執(zhí)行函數(shù)】進宏微任務

處理 watcher 更新隊列 queue

當 flushing 為 false時,表示 queue 還沒有開始遍歷執(zhí)行,直接 push

當 flushing 為 true,表示 queue 已經(jīng)開始遍歷,執(zhí)行其中的 watcher 更新了

然后,做了一個很特殊的插入操作(為了方便看,把上面的源碼截取了)

我還是沒有看懂這是為什么? 直到我看到了 flushSchedulerQueue 的 源碼!

因為在 flushSchedulerQueue 執(zhí)行的時候(此時設置了 flushing = true),內部把 queue 升序排列了!

所以在 flushing 的時候,queue已經(jīng)是有序狀態(tài),中途進來的 watcher,當然也要按順序來

所以,這一段的作用就是給 新來的 watcher 排序!

其中 index 表示 現(xiàn)在正遍歷到第幾個 watcher(在 flushSchedulerQueue 中設置)

所以,也必然是排到已經(jīng)執(zhí)行過的 watcher 后面的(不然就遍歷不到這個watcher 了?。?/p> 注冊 【watcher 更新隊列 執(zhí)行函數(shù)】進宏微任務

已經(jīng)講到 flushSchedulerQueue 了,他就是 注冊宏微任務的異步回調

直接存放進 異步任務隊列 callbacks 中的

關于 nextTick 的 異步任務隊列 ,可以看

NextTick - 源碼版 之 獨立自身

接下來,就看 flushSchedulerQueue

執(zhí)行更新隊列
function flushSchedulerQueue() {



    flushing = true;    

    var watcher;    

    

    // 升序排列

    queue.sort(function(a, b) {        

        return a.id - b.id;

    });    

    

    for (index = 0; index < queue.length; index++) {

        watcher = queue[index];
        has[watcher.id] = null;
        watcher.run();
    }    



    // 所有watcher 完成更新,重置狀態(tài)

    queue.length = 0;
    has = {};
    waiting = flushing = false;

}
flushSchedulerQueue 的作用

1、升序排列 watcher 更新隊列

2、遍歷 watcher 更新隊列,然后逐個調用 watcher 更新

3、watcher 更新隊列執(zhí)行完畢,重置狀態(tài)

其他我都看得明白,唯獨我不懂一個問題

為什么要把 queue 按照 watcher.id 升序排列??

首先,watcher.id 越大,表示這個 watcher 越年輕,實例是越后面生成的

vue 的官方回答

This ensures that:

Components are updated from parent to child. (because parent is always created before the child)

A component"s user watchers are run before its render watcher (because user watchers are created before the render watcher)

If a component is destroyed during a parent component"s watcher run, its watchers can be skipped.

我只挑一點

先更新父組件,再更新子組件(因為父組件比子組件先創(chuàng)建)

為什么先更新父組件,再更新子組件,我還是想不通???

個人認為,因為父組件跟子組件是有聯(lián)系的,什么聯(lián)系呢?

比如 props

當 父組件傳給子組件的數(shù)據(jù)變化的時候,父組件需要把 變化后的數(shù)據(jù) 傳給 子組件,子組件才能知道數(shù)據(jù)變了

那么 子組件才能更新組件內使用 props 的地方

所以,父組件必須先更新,把最新數(shù)據(jù)傳給 子組件,子組件再更新,此時才能獲取最新的數(shù)據(jù)

不然你子組件更新了,父組件再傳數(shù)據(jù)過來,那就不會子組件就不會顯示最新的數(shù)據(jù)了啊

至于 父組件更新時怎么傳 數(shù)據(jù)給子組件的?

【Vue原理】Props - 白話版

最后,走個簡單流程

數(shù)據(jù)變化,通知 watcher 更新,watcher.update

queueWatcher 把 watcher 添加進 【queue 更新隊列】

把 flushSchedulerQueue 注冊進宏微任務

JS 主棧執(zhí)行完,開始執(zhí)行異步代碼

flushSchedulerQueue 遍歷 queue ,逐個調用 watcher 更新

完成更新

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://www.ezyhdfw.cn/yun/110259.html

相關文章

  • Vue原理NextTick - 源碼 獨立自身

    摘要:盡量把所有異步代碼放在一個宏微任務中,減少消耗加快異步代碼的執(zhí)行。我們知道,如果一個異步代碼就注冊一個宏微任務的話,那么執(zhí)行完全部異步代碼肯定慢很多避免頻繁地更新。中就算我們一次性修改多次數(shù)據(jù),頁面還是只會更新一次。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5...

    劉東 評論0 收藏0
  • Vue原理NextTick - 源碼 宏微任務的抉擇

    摘要:這么講,有點籠統(tǒng),準確地說,應該是事件回調執(zhí)行過程中,在主線程為空之后,異步代碼執(zhí)行之前,所有通過注冊的異步代碼都是用宏任務。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【...

    raise_yang 評論0 收藏0
  • Vue原理NextTick - 白話

    摘要:通常會做很多判斷來選擇存在的類型,比如判斷等是否存在,而選擇他為微任務類型但是可能宏微任務最后都是,因為他是保守兼容處理。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【V...

    zeyu 評論0 收藏0
  • 前方來報,八月最新資訊--關于vue2&3的最佳文章推薦

    摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運,我不曉得。我只曉得,不認命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...

    izhuhaodev 評論0 收藏0
  • 迷你Vue--學習如何造一個Vue輪子

    摘要:項目地址和的區(qū)別其實和最大的區(qū)別就是多了一個虛擬,其他的區(qū)別都是很小的。 項目地址 Vue1和Vue2的區(qū)別 其實Vue1和Vue2最大的區(qū)別就是Vue2多了一個虛擬DOM,其他的區(qū)別都是很小的。所以理解了Vue1的源碼,就相當于理解了Vue2,中間差了一個虛擬DOM的Diff算法 文檔 數(shù)據(jù)雙向綁定 Vue主流程走向 組件 nextTick異步更新 MVVM 先來科普一下MVVM...

    isLishude 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<