Vue3源碼解析(computed-計算屬性)

exportfunctioncomputed(getter: ComputedGetter<T>):ComputedRefexportfunctioncomputed( options: WritableComputedOptions<T>):WritableComputedRefexportfunctioncomputed( getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>){letgetter:ComputedGetterletsetter:ComputedSetterif(isFunction(getterOrOptions)){getter=getterOrOptionssetter=NOOP}else{ getter = getterOrOptions.get setter = getterOrOptions.set }returnnewComputedRefImpl( getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set )asany}

在最開始使用函數(shù)重載的方式允許computed函數(shù)接受兩種類型的參數(shù):第一種是一個getter函數(shù), 第二種是一個帶getset的對象潘鲫。

接下就是在函數(shù)內(nèi)部根據(jù)傳入的不同類型的參數(shù)初始化函數(shù)內(nèi)部的getter和setter函數(shù),如果傳入的是一個函數(shù)類型的參數(shù),那么getter就是這個函數(shù)毅待,setter就是一個空的操作,如果傳入的參數(shù)是一個對象,則getter就等于這個對象的get函數(shù),setter就等于這個對象的set函數(shù)别凹。

在函數(shù)的結(jié)尾返回了一個new ComputedRefImpl,并將前面我們標(biāo)準(zhǔn)化后的參數(shù)傳遞給了這個構(gòu)造函數(shù)。

下面我們就來分析一下ComputedRefImpl這個構(gòu)造函數(shù)。

ComputedRefImpl

classComputedRefImpl{// 緩存結(jié)果private _value!: T// 重新計算開關(guān)private _dirty =truepublic readonly effect: ReactiveEffect? public readonly __v_isRef =true;? public readonly [ReactiveFlags.IS_READONLY]: booleanconstructor(? ? getter: ComputedGetter<T>,

? ? private readonly _setter: ComputedSetter<T>,

? ? isReadonly: boolean

? ){// 對傳入的getter函數(shù)進行包裝this.effect = effect(getter, {lazy:true,// 調(diào)度執(zhí)行scheduler:() =>{if(!this._dirty) {this._dirty =true// 派發(fā)通知trigger(toRaw(this), TriggerOpTypes.SET,'value')? ? ? ? }? ? ? }? ? })? }// 訪問計算屬性的時候 默認(rèn)調(diào)用此時的get函數(shù)getvalue() {// 是否需要重新計算if(this._dirty) {this._value =this.effect()this._dirty =false}// 訪問的時候進行依賴收集 此時收集的是訪問這個計算屬性的副作用函數(shù)track(toRaw(this), TrackOpTypes.GET,'value')returnthis._value? }setvalue(newValue: T) {this._setter(newValue)? }}

ComputedRefImpl類在內(nèi)部維護了_value和_dirty這兩個非常重要的私有屬性,其中_value使用用來緩存我們計算的結(jié)果官份,_dirty是用來控制是否需要重現(xiàn)計算。接下來我們來看一下這個函數(shù)的內(nèi)部運行機制。

首先構(gòu)造函數(shù)在初始化的時候使用了effect函數(shù)對傳入getter進行了一層包裝(上一篇文章中我們分析過effect函數(shù)的作用就是將傳入的函數(shù)變成可響應(yīng)式的副作用函數(shù)),但是這里我們在effect中傳入了一些配置參數(shù)肥惭,還記得前面我們分析trigger函數(shù)的時候有這一段代碼:

construn =(effect: ReactiveEffect) =>{if(effect.options.scheduler) {? ? ? effect.options.scheduler(effect)? ? }else{? ? ? effect()? ? }? }effects.forEach(run)

當(dāng)屬性值發(fā)生改變之后,會觸發(fā)trigger函數(shù)進行派發(fā)更新紊搪,將所有依賴這個屬性的effect函數(shù)循環(huán)遍歷,使用run函數(shù)執(zhí)行effect,如果effect的參數(shù)中配置了scheduler蜜葱,則就執(zhí)行scheduler函數(shù),而不是執(zhí)行依賴的副作用函數(shù)嗦明。當(dāng)計算屬性依賴的屬性發(fā)生變化的時候笼沥,回執(zhí)行包裝getter函數(shù)的effect, 但是因為配置了scheduler函數(shù),所以真正執(zhí)行的是scheduler函數(shù)娶牌,在scheduler函數(shù)中并沒有執(zhí)行計算屬性的getter函數(shù)求取新值,而是將_dirty設(shè)置為false,然后通知依賴計算屬性的副作用函數(shù)進行更新, 當(dāng)依賴計算屬性的副作用函數(shù)收到通知的時候就會訪問計算屬性的get函數(shù)奔浅,此時會根據(jù)_dirty值來確定是否需要重新計算。

回到我們的這個構(gòu)造函數(shù)中诗良,只需要記得我們在構(gòu)造函數(shù)初始化三個重要的點:第一:對傳入的getter函數(shù)使用effect函數(shù)進行包裝汹桦。第二:在使用effect包裝的過程中,我們會執(zhí)行g(shù)etter函數(shù)鉴裹,此時getter函數(shù)執(zhí)行過程中對于訪問到的屬性會將當(dāng)前的這個計算屬性收集到對應(yīng)的依賴集合中,?第三:傳入了配置參數(shù)lazy和scheduler舞骆,這些配置參數(shù)在當(dāng)前的這個計算屬性所訂閱的屬性發(fā)生改變的時候,用來控制計算屬性的調(diào)度時機径荔。

接著我們繼續(xù)分析get value,當(dāng)我們訪問計算屬性的值時候?qū)嶋H上訪問的就是這個函數(shù)的返回值, 它會根據(jù)_dirty的值來判斷是否需要重新計算getter函數(shù)督禽,_dirty為true需要重新執(zhí)行effect函數(shù),并將effect的值置為false总处,否則就返回之前緩存的_value值狈惫。在訪問計算屬性值的階段會調(diào)用track函數(shù)進行依賴收集,此時收集的是訪問計算屬性值的副作用函數(shù), key始終是vlaue鹦马。

最后就是當(dāng)設(shè)置計算屬性的值的時候會執(zhí)行set函數(shù),然后調(diào)用我們傳入的_setter函數(shù)胧谈。

示例流程

至此計算屬性的執(zhí)行流程就分析完畢了,我們來結(jié)合一個示例來完整的過一遍整個流程:

龍華大道1號 http://www.kinghill.cn/Dynamics/2106.html

add

計算屬性:{{computedData}}

import{ ref, watch,reactive, computed }from'vue'import{ effect }from'@vue/reactivity'exportdefault{name:'App',setup(){consttestData = ref(1)constcomputedData = computed(() =>{returntestData.value++? ? })functionaddNum(){? ? ? testData.value +=10}return{? ? ? addNum,? ? ? computedData? ? }? },}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荸频,一起剝皮案震驚了整個濱河市菱肖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旭从,老刑警劉巖稳强,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件场仲,死亡現(xiàn)場離奇詭異,居然都是意外死亡键袱,警方通過查閱死者的電腦和手機燎窘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹄咖,“玉大人褐健,你說我怎么就攤上這事±教溃” “怎么了蚜迅?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長俊抵。 經(jīng)常有香客問我谁不,道長,這世上最難降的妖魔是什么徽诲? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任刹帕,我火速辦了婚禮,結(jié)果婚禮上谎替,老公的妹妹穿的比我還像新娘偷溺。我一直安慰自己,他們只是感情好钱贯,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布挫掏。 她就那樣靜靜地躺著,像睡著了一般秩命。 火紅的嫁衣襯著肌膚如雪尉共。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天弃锐,我揣著相機與錄音袄友,去河邊找鬼。 笑死霹菊,一個胖子當(dāng)著我的面吹牛杠河,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浇辜,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唾戚!你這毒婦竟也來了柳洋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤叹坦,失蹤者是張志新(化名)和其女友劉穎熊镣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡绪囱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年测蹲,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鬼吵。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡扣甲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出齿椅,到底是詐尸還是另有隱情琉挖,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布涣脚,位于F島的核電站示辈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏遣蚀。R本人自食惡果不足惜矾麻,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芭梯。 院中可真熱鬧险耀,春花似錦、人聲如沸粥帚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芒涡。三九已至柴灯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間费尽,已是汗流浹背赠群。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旱幼,地道東北人查描。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像柏卤,于是被迫代替她去往敵國和親冬三。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容