国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【Vue原理】Computed - 源碼版

solocoder / 2369人閱讀

摘要:被讀取,包裝的函數(shù)觸發(fā),第一次會進(jìn)行計(jì)算被調(diào)用,進(jìn)而被調(diào)用,被設(shè)置為,舊值頁面被緩存起來。計(jì)算會讀取,此時(shí)就收集到同時(shí)也會保存到的依賴收集器用于下一步。

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

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

【Vue原理】Computed - 源碼版

今天要記錄 computed 的源碼,有時(shí)候想,理解不就好了嗎,為什么要記錄一遍源碼。現(xiàn)在終于想通了

過了一段時(shí)間之后,你就會忘記你的所謂理解是怎么來的

“哎,為什么會這么做,關(guān)系為什么是這樣,我c....”

于是,記錄并簡化源碼,就有助我們迅速找到根源,解決我們的疑惑,還能加強(qiáng)我們的理解

好吧

嗯,這篇文章很長很詳細(xì)哦,做好閱讀的準(zhǔn)備,唔該

我們重點(diǎn)說明,幾個(gè)問題的源碼實(shí)現(xiàn)

1、computed 的 月老身份的來源

2、computed 怎么計(jì)算

3、computed 的緩存是怎么做的

4、computed 什么時(shí)候初始化

5、computed 是怎么可以直接使用實(shí)例訪問到的

問題不會按順序解析,因?yàn)檫@些問題會互相關(guān)聯(lián),在探索源碼的過程中,你自然會得到答案

首先,從這個(gè)問題開始我們今天的探索之旅,請看源碼

什么時(shí)候初始化
function Vue(){
    ... 其他處理
    initState(this)

    ...解析模板,生成DOM 插入頁面

}



function initState(vm) {    

    var opts = vm.$options;    

    if (opts.computed) { 

        initComputed(vm, opts.computed); 

    }

    .....

}

沒錯(cuò),當(dāng)你調(diào)用 Vue 創(chuàng)建實(shí)例過程中,會去處理各種選項(xiàng),其中包括處理 computed

處理 computed 的方法是 initComputed,下面就呈上 源碼

initComputed
function initComputed(vm, computed) {    

    var watchers = vm._computedWatchers = 

            Object.create(null);    

    for (var key in computed) {        

        var userDef = computed[key];        

        var getter = 

            typeof userDef === "function" ? 

                userDef: userDef.get;      



        // 每個(gè) computed 都創(chuàng)建一個(gè) watcher

        // watcher 用來存儲計(jì)算值,判斷是否需要重新計(jì)算

        watchers[key] = 

        new Watcher(vm, getter, { 

             lazy: true 

        });        

        

        // 判斷是否有重名的屬性

        if (! (key in vm)) {
            defineComputed(vm, key, userDef);
        }
    }
}

initComputed 這段代碼做了幾件事

1、每個(gè) computed 配發(fā) watcher

2、defineComputed 處理

3、收集所有 computed 的 watcher

好的,這三件事,一件一件說哈

1、每個(gè) computed 配發(fā) watcher

computed 到底和 watcher 有什么貓膩呢?

1、保存 computed 計(jì)算函數(shù)

2、保存計(jì)算結(jié)果

3、控制緩存計(jì)算結(jié)果是否有效

看下 Watcher 源碼構(gòu)造函數(shù)

function Watcher(vm, expOrFn, options) {    

    this.dirty = this.lazy = options.lazy;    

    this.getter = expOrFn;    

    this.value = this.lazy ? undefined: this.get();

};

從這段源碼中,我們再看 computed 傳了什么參數(shù)

new Watcher(vm, getter, { lazy: true })

于是,我們就知道了上面說的三個(gè)貓膩是怎么回事

1、保存設(shè)置的 getter。

把用戶設(shè)置的 computed-getter,存放到 watcher.getter 中,用于后面的計(jì)算

2、watcher.value 存放計(jì)算結(jié)果,但是這里有個(gè)條件,因?yàn)?lazy 的原因,不會新建實(shí)例并馬上讀取值

這里可以算是 Vue 的一個(gè)優(yōu)化,只有你再讀取 computed,再開始計(jì)算,而不是初始化就開始計(jì)算值了

雖然沒有一開始計(jì)算,但是計(jì)算 value 還是這個(gè) watcher.get 這個(gè)方法,來看下源碼(已省略部分代碼,下面講其他問題,會更詳細(xì)展示出來)

這個(gè)方法,其實(shí)就是執(zhí)行 保存的 getter 函數(shù),從而得到計(jì)算值,灰常簡單

Watcher.prototype.get = function() {    

    // getter 就是 watcher 回調(diào)

    var value = this.getter.call(vm, vm);    

    return value

};

3、computed 新建 watcher 的時(shí)候,傳入 lazy

沒錯(cuò),作用是把計(jì)算結(jié)果緩存起來,而不是每次使用都要重新計(jì)算

而這里呢,還把 lazy 賦值給了 dirty,為什么呢?

因?yàn)?lazy 表示一種固定描述,不可改變,表示這個(gè) watcher 需要緩存

而 dirty 表示緩存是否可用,如果為 true,表示緩存臟了,需要重新計(jì)算,否則不用

dirty 默認(rèn)是 false 的,而 lazy 賦值給 dirty,就是給一個(gè)初始值,表示 你控制緩存的任務(wù)開始了

所以記住,【dirty】 是真正的控制緩存的關(guān)鍵,而 lazy 只是起到一個(gè)開啟的作用

具體,怎么控制緩存,下面會說

2、defineComputed 處理

請看源碼

function defineComputed(

    target, key, userDef

) {    

    // 設(shè)置 set 為默認(rèn)值,避免 computed 并沒有設(shè)置 set

    var set = function(){}      
    //  如果用戶設(shè)置了set,就使用用戶的set

    if (userDef.set) set = userDef.set   



    Object.defineProperty(target, key, {        

        // 包裝get 函數(shù),主要用于判斷計(jì)算緩存結(jié)果是否有效

        get:createComputedGetter(key),        

        set:set

    });
}

源碼已經(jīng)被我簡短很多,但是意思是不變的

1、使用 Object.defineProperty 在 實(shí)例上computed 屬性,所以可以直接訪問

2、set 函數(shù)默認(rèn)是空函數(shù),如果用戶設(shè)置,則使用用戶設(shè)置

3、createComputedGetter 包裝返回 get 函數(shù)

重點(diǎn)就在第三點(diǎn),為什么重要?

兩大問題都在這里得到解決,【月老牽線問題+緩存控制問題】

馬上呈上 createComputedGetter 源碼

function createComputedGetter(key) {    

    return function() {        

        // 獲取到相應(yīng) key 的 computed-watcher

        var watcher = this._computedWatchers[key];        

        // 如果 computed 依賴的數(shù)據(jù)變化,dirty 會變成true,

                    從而重新計(jì)算,然后更新緩存值 watcher.value

        if (watcher.dirty) {
            watcher.evaluate();

        }        

        // 這里是 月老computed 牽線的重點(diǎn),讓雙方建立關(guān)系

        if (Dep.target) {
            watcher.depend();

        }        

        return watcher.value

    }
}
1、緩存控制

下面這段代碼作用就是緩存控制,請往下看

if (watcher.dirty) {       

    watcher.evaluate()

}

1、watcher.evaluate 用來重新計(jì)算,更新緩存值,并重置 dirty 為false,表示緩存已更新

下面是源碼

Watcher.prototype.evaluate = function() {    

    this.value = this.get();    

    // 執(zhí)行完更新函數(shù)之后,立即重置標(biāo)志位

    this.dirty = false;
};

2、只有 dirty 為 true 的時(shí)候,才會執(zhí)行 evaluate

所有說通過 控制 dirty 從而控制緩存,但是怎么控制dirty 呢?

先說一個(gè)設(shè)定,computed數(shù)據(jù)A 引用了 data數(shù)據(jù)B,即A 依賴 B,所以B 會收集到 A 的 watcher

當(dāng) B 改變的時(shí)候,會通知 A 進(jìn)行更新,即調(diào)用 A-watcher.update,看下源碼

Watcher.prototype.update = function() {    

    if (this.lazy)  this.dirty = true;

    ....還有其他無關(guān)操作,已被省略

};

當(dāng)通知 computed 更新的時(shí)候,就只是 把 dirty 設(shè)置為 true,從而 讀取 comptued 時(shí),便會調(diào)用 evalute 重新計(jì)算

2、月老牽線

月老牽線的意思,在白話版中也說清楚了,這里簡單說一下

現(xiàn)有 頁面-P,computed- C,data- D

1、P 引用了 C,C 引用了 D

2、理論上 D 改變時(shí), C 就會改變,C 則通知 P 更新。

3、實(shí)際上 C 讓 D 和 P 建立聯(lián)系,讓 D 改變時(shí)直接通知 P

沒錯(cuò),就是下面這段代碼搞的鬼

if (Dep.target) {
   watcher.depend();
}

你別看這段代碼短啊,涉及的內(nèi)容真不少啊且需要點(diǎn)腦筋的,看源碼分分鐘繞不過來,真的服尤大怎么寫出來的

來看看 watcher.depend 的源碼

Watcher.prototype.depend = function() {    

    var i = this.deps.length;    

    while (i--) {        

        // this.deps[i].depend();

        dep.addSub(Dep.target)
    }
};

這段的作用就是!(依然使用上面的例子 PCD 代號來說明)

讓 D 的依賴收集器收集到 Dep.target,而 Dep.target 當(dāng)前是什么?

沒錯(cuò),就是 頁面 的 watcher!

所以這里,D 就會收集到 頁面的 watcher 了,所以就會直接通知 頁面 watcher

看累了嗎.....

你會問了,為什么 Dep.target 是 頁面 watcher?

你好,這里內(nèi)容就有點(diǎn)多了有點(diǎn)繁雜了,坐好了兄die

先送你一份源碼大禮,收好了

Watcher.prototype.get = function() {    
    // 改變 Dep.target

    pushTarget()    

    // getter 就是 watcher 回調(diào)

    var value = this.getter.call(this.vm, this.vm);    
    // 恢復(fù)前一個(gè) watcher

    popTarget()    

    return value

};



Dep.target = null;

var targetStack = [];

function pushTarget(_target) {    

    // 把上一個(gè) Dep.target 緩存起來,便于后面恢復(fù)

    if (Dep.target) {
        targetStack.push(Dep.target);
    }
    Dep.target = _target;

}



function popTarget() {

    Dep.target = targetStack.pop();
}

注解幾個(gè)詞

1、頁面 watcher.getter 保存 頁面更新函數(shù),computed watcher.getter 保存 計(jì)算getter

2、watcher.get 用于執(zhí)行 watcher.getter 并 設(shè)置 Dep.target

3、Dep.target 會有緩存

下面開始 月老牽線的 詳細(xì)流程

1、頁面更新,讀取 computed 的時(shí)候,Dep.target 會設(shè)置為 頁面 watcher。

2、computed 被讀取,createComputedGetter 包裝的函數(shù)觸發(fā),第一次會進(jìn)行計(jì)算

computed-watcher.evaluted 被調(diào)用,進(jìn)而 computed-watcher.get 被調(diào)用,Dep.target 被設(shè)置為 computed-watcher,舊值 頁面 watcher 被緩存起來。

3、computed 計(jì)算會讀取 data,此時(shí) data 就收集到 computed-watcher

同時(shí) computed-watcher 也會保存到 data 的依賴收集器 dep(用于下一步)。

computed 計(jì)算完畢,釋放Dep.target,并且Dep.target 恢復(fù)上一個(gè)watcher(頁面watcher)

4、手動 watcher.depend, 讓 data 再收集一次 Dep.target,于是 data 又收集到 恢復(fù)了的頁面watcher

再額外記一個(gè)data改變后續(xù)流程

綜上,此時(shí) data 的依賴收集器=【computed-watcher,頁面watcher】

data 改變,正序遍歷通知,computed 先更新,頁面再更新,所以,頁面才能讀取到最新的 computed 值

3、收集所有 computed 的 watcher

從源碼中,你可以看出為每個(gè)computed 新建watcher 之后,會全部收集到一個(gè)對象中,并掛到實(shí)例上

為什么收集起來,我暫時(shí)的想法是

為了在 createComputedGetter 獲取到對應(yīng)的 watcher

其實(shí)可以通過傳遞 watcher ,但是這里的做法是傳遞 key,然后使用key 去找到對應(yīng) watcher

哎喲,我的媽,終于寫完了,瞧瞧多少字,7000多,寫得我

場外:尼瑪大部分是源碼好嗎

okok,行行行

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

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105381.html

相關(guān)文章

  • Vue原理】月老Computed - 白話

    摘要:如果沒有緩存,我們將不可避免的多次執(zhí)行的現(xiàn)在我們要開始講解,是如何判斷是否使用緩存的首先計(jì)算后,會把計(jì)算得到的值保存到一個(gè)變量中。當(dāng)使用緩存時(shí),就直接返回這個(gè)變量。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點(diǎn)擊 下面鏈接 或...

    Tony_Zby 評論0 收藏0
  • Vue原理】Props - 源碼

    寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】Props - 源碼版 今天記錄 Props 源碼流程,哎,這東西,就算是研究過了,也真是會隨著時(shí)間慢慢忘記的。 幸好我做...

    light 評論0 收藏0
  • Vue原理】Mixins - 源碼

    寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】Mixins - 源碼版 今天探索的是 mixins 的源碼,mixins 根據(jù)不同的選項(xiàng)類型會做不同的處理 篇幅會有些長,...

    gotham 評論0 收藏0
  • Vue原理】響應(yīng)式原理 - 白話

    摘要:所以我今后打算把每一個(gè)內(nèi)容分成白話版和源碼版。有什么錯(cuò)誤的地方,感謝大家能夠指出響應(yīng)式系統(tǒng)我們都知道,只要在實(shí)例中聲明過的數(shù)據(jù),那么這個(gè)數(shù)據(jù)就是響應(yīng)式的。什么是響應(yīng)式,也即是說,數(shù)據(jù)發(fā)生改變的時(shí)候,視圖會重新渲染,匹配更新為最新的值。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 V...

    gggggggbong 評論0 收藏0
  • Vue原理】依賴收集 - 源碼之基本數(shù)據(jù)類型

    摘要:當(dāng)東西發(fā)售時(shí),就會打你的電話通知你,讓你來領(lǐng)取完成更新。其中涉及的幾個(gè)步驟,按上面的例子來轉(zhuǎn)化一下你買東西,就是你要使用數(shù)據(jù)你把電話給老板,電話就是你的,用于通知老板記下電話在電話本,就是把保存在中。剩下的步驟屬于依賴更新 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【...

    VincentFF 評論0 收藏0

發(fā)表評論

0條評論

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