成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【Vue原理】NextTick - 源碼版 之 服務(wù)Vue

Acceml / 1609人閱讀

寫(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)單了解下NextTick

好的,今天,就來(lái)詳細(xì)記錄 Vue 和 nextTick 的那些事

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

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

上篇文章

NextTick-源碼版之獨(dú)立自身
提到過(guò),nextTick 幫助 Vue 避免頻繁的更新,這里簡(jiǎn)單提一下,

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

也就是說(shuō)數(shù)據(jù)被修改的時(shí)候,會(huì)調(diào)用一遍【引用這個(gè)數(shù)據(jù)的實(shí)例】的更新函數(shù)

那么,按道理來(lái)說(shuō),修改3次,就應(yīng)該調(diào)用3遍更新函數(shù),但是實(shí)際上只會(huì)調(diào)用一遍

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

結(jié)果就是只打印一次

至于依賴(lài)更新,可以看下面的文章

依賴(lài)更新 - 源碼版

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

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

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

每個(gè)實(shí)例都會(huì)通過(guò) new Vue 生成的,所以會(huì)有一個(gè)專(zhuān)屬的 watcher

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

function Vue(){
    ....
    new Watcher(vm, 實(shí)例更新函數(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 是響應(yīng)式的,就是通過(guò) Object.defineProperty 設(shè)置 get 和 set

當(dāng)數(shù)據(jù)被修改的時(shí)候, set 函數(shù)被觸發(fā),函數(shù)內(nèi)部會(huì)通知所有的實(shí)例進(jìn)行更新(就是調(diào)用每個(gè)實(shí)例的 watcher.update 方法)

具體可以看這個(gè)

響應(yīng)式原理 - 白話版
依賴(lài)更新 - 源碼版

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

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

更新隊(duì)列

速度看源碼!

var queue = [];

var has = {};

var index = 0;

var flushing = false;

var waiting= false;



function queueWatcher(watcher) {  



    var id = watcher.id;    



    // 如果是同一個(gè) Vue 實(shí)例,就不要重復(fù)添加了

    if (has[id] == null) {                
              

        // 這個(gè)實(shí)例已經(jīng)被標(biāo)記了

        has[id] = true;        



        // 如果沒(méi)有在運(yùn)行,那么直接放入隊(duì)列

        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;            



            // 跳過(guò)所有比我大的

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

         

            // 最后放在隊(duì)列中,一個(gè)比我老的 watcher 后面

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



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

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

先說(shuō)說(shuō)其中涉及的幾個(gè)變量

has

是一個(gè)對(duì)象,用來(lái)過(guò)濾watcher。

當(dāng)這個(gè)watcher 已經(jīng)調(diào)用過(guò)更新函數(shù),那么就在 has 中標(biāo)記這個(gè) id

也就是,你同時(shí)間調(diào)用多次 watcher.update ,其實(shí)只有第一次調(diào)用有用,后面的都會(huì)被過(guò)濾掉

queue

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

flushSchedulerQueue

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

waiting

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

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

flushing

為 true 表示 watcher 更新隊(duì)列正在執(zhí)行更新(就是開(kāi)始遍歷 watcher 隊(duì)列,逐個(gè)調(diào)用 watcher 更新了)

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

queueWatcher 源碼不算很復(fù)雜,主要做兩件事

1、處理watcher 更新隊(duì)列 queue

2、注冊(cè) 【watcher 更新隊(duì)列 執(zhí)行函數(shù)】進(jìn)宏微任務(wù)

處理 watcher 更新隊(duì)列 queue

當(dāng) flushing 為 false時(shí),表示 queue 還沒(méi)有開(kāi)始遍歷執(zhí)行,直接 push

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

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

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

因?yàn)樵?flushSchedulerQueue 執(zhí)行的時(shí)候(此時(shí)設(shè)置了 flushing = true),內(nèi)部把 queue 升序排列了!

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

所以,這一段的作用就是給 新來(lái)的 watcher 排序!

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

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

已經(jīng)講到 flushSchedulerQueue 了,他就是 注冊(cè)宏微任務(wù)的異步回調(diào)

直接存放進(jìn) 異步任務(wù)隊(duì)列 callbacks 中的

關(guān)于 nextTick 的 異步任務(wù)隊(duì)列 ,可以看

NextTick - 源碼版 之 獨(dú)立自身

接下來(lái),就看 flushSchedulerQueue

執(zhí)行更新隊(duì)列
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 更新隊(duì)列

2、遍歷 watcher 更新隊(duì)列,然后逐個(gè)調(diào)用 watcher 更新

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

其他我都看得明白,唯獨(dú)我不懂一個(gè)問(wèn)題

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

首先,watcher.id 越大,表示這個(gè) watcher 越年輕,實(shí)例是越后面生成的

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.

我只挑一點(diǎn)

先更新父組件,再更新子組件(因?yàn)楦附M件比子組件先創(chuàng)建)

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

個(gè)人認(rèn)為,因?yàn)楦附M件跟子組件是有聯(lián)系的,什么聯(lián)系呢?

比如 props

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

那么 子組件才能更新組件內(nèi)使用 props 的地方

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

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

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

【Vue原理】Props - 白話版

最后,走個(gè)簡(jiǎn)單流程

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

queueWatcher 把 watcher 添加進(jìn) 【queue 更新隊(duì)列】

把 flushSchedulerQueue 注冊(cè)進(jìn)宏微任務(wù)

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

flushSchedulerQueue 遍歷 queue ,逐個(gè)調(diào)用 watcher 更新

完成更新

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/110259.html

相關(guān)文章

  • Vue原理NextTick - 源碼 獨(dú)立自身

    摘要:盡量把所有異步代碼放在一個(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...

    劉東 評(píng)論0 收藏0
  • Vue原理NextTick - 源碼 宏微任務(wù)的抉擇

    摘要:這么講,有點(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)也可以吧 【...

    raise_yang 評(píng)論0 收藏0
  • Vue原理NextTick - 白話

    摘要:通常會(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...

    zeyu 評(píng)論0 收藏0
  • 前方來(lái)報(bào),八月最新資訊--關(guān)于vue2&3的最佳文章推薦

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

    izhuhaodev 評(píng)論0 收藏0
  • 迷你Vue--學(xué)習(xí)如何造一個(gè)Vue輪子

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

    isLishude 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<