欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue源碼解析computed多次訪問會有死循環(huán)原理

 更新時間:2023年04月04日 15:19:54   作者:Mr_shaojun  
這篇文章主要為大家介紹了vue源碼解析computed多次訪問會有死循環(huán)原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

在上一篇中,我們仿vue源碼自己實現(xiàn)了一個computed。

寫了如下的測試代碼。

    const { reactive, effect, ref, computed } = Vue
      const obj = reactive({
        name: '張三'
      })
      // C1
      const computedObj = computed(() => {
        console.log('computed')
        return '姓名:' + obj.name
      })
      // e1
      effect(() => {
        document.querySelector('#app').innerHTML = computedObj.value
        document.querySelector('#app').innerHTML = computedObj.value
      })
      setTimeout(() => {
        obj.name = '李四'
      }, 2000)

我們發(fā)現(xiàn)computed多次訪問的時候,會出現(xiàn)死循環(huán)。

為什么會有死循環(huán)

這個問題出在哪了呢?

我們先看一下這段代碼的執(zhí)行情況。(當時看源碼,我也是理了好幾遍,才理出頭緒。有條件的話,還是建議clone代碼自己調試一遍)

我們直接看effect。

1.先執(zhí)行effect函數(shù),設置activeEffect為傳進來的參數(shù),也就是掛載dom的這個函數(shù),我們把這個函數(shù)就叫e1。

//叫e1
() => {
   document.querySelector('#app').innerHTML = computedObj.value
   document.querySelector('#app').innerHTML = computedObj.value
}

2.執(zhí)行e1函數(shù)

第一次執(zhí)行computedObj.value,此時會執(zhí)行如下代碼。

先是收集依賴,將e1收集起來;

【此時,key為computedObj, activeEffect為e1】

因為此時,_dirty是true,所以會執(zhí)行computed計算函數(shù)。

執(zhí)行effect.run,也就是下面這段邏輯,我們把這個函數(shù)叫做c1

// 叫c1
() => {
  console.log('con')
  return '姓名:' + obj.name
}

執(zhí)行obj.name 觸發(fā)reactive的get,將C1收集起來。

【此時,key為obj, activeEffect被改為C1】

3 第二次執(zhí)行computedObj.value

依舊會觸發(fā)一次依賴收集。

【此時,key為computedObj, activeEffect已經被改為為C1了】

此時_dirty為false,則不會執(zhí)行計算。

effct執(zhí)行完畢,此時computedObj有兩個依賴,分別是e1和c1。obj上有一個依賴,為c1

4.在2秒后,觸發(fā)obj.name的set事件,則觸發(fā)obj上的依賴函數(shù),開始遍歷執(zhí)行。

注意,因為computed中使用了scheduler,所以此時的c1。

所以會執(zhí)行如下代碼

    this.effect = new ReactiveEffect(getter, () => {
      // 判斷當前臟的狀態(tài),如果為 false,表示需要《觸發(fā)依賴》
      if (!this._dirty) {
        // 將臟置為 true,表示
        this._dirty = true
        triggerRefValue(this)
      }
    })

5.執(zhí)行triggerRefValue(this)

triggerRefValue(this)會觸發(fā)computedObj上的依賴。

此時dirty = true, 并遍歷執(zhí)行e1,c1依賴函數(shù)。

  for (const effect of effects) {
     triggerEffect(effect)
  }

6.當執(zhí)行e1函數(shù)時,又會觸發(fā)computed.get,并將e1加入依賴。

此時【key為computedObj, activeEffect為e1】

由于此時,_dirty是true,則又會執(zhí)行run,重新計算。

此時【key為, activeEffect為c1】

7.當執(zhí)行c1時,因為之前e1函數(shù)已經將_dirty改為false了,于是又會開始執(zhí)行triggerRefValue(this),遍歷computedObj上的依賴c1和e1。

因為此時computedObj依舊是有e1和c1兩個依賴,又會重新回到第5步,造成死循環(huán)。

如何解決死循環(huán)

那找到了問題,如何解決呢?

其實方法也很簡單,在第6步的時候,我們只要確保讓c1先執(zhí)行,e1后執(zhí)行就行,

先執(zhí)行c1時,因為此時dirty是true,所以不會重復執(zhí)行triggerRefValue(this)。

然后再執(zhí)行e1,添加依賴。

vue源碼也是這么實現(xiàn)的,先把computed的依賴執(zhí)行完,然后再執(zhí)行其他依賴。

這也就是為什么,vue源碼中觸發(fā)依賴,有兩次遍歷。

export function triggerEffects(
  dep: Dep | ReactiveEffect[],
  debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
  // spread into array for stabilization
  const effects = isArray(dep) ? dep : [...dep]
  for (const effect of effects) {
    if (effect.computed) {
      triggerEffect(effect, debuggerEventExtraInfo)
    }
  }
  for (const effect of effects) {
    if (!effect.computed) {
      triggerEffect(effect, debuggerEventExtraInfo)
    }
  }
}

總結

不管是數(shù)據(jù)的響應式,還是computed的實現(xiàn),亦或是vue組件的更新。

本質都是通過effec偵聽器來實現(xiàn)的。

對于effec有幾點要理解清楚。

1.activeEffect是會不斷變化的,這就導致,同樣的代碼,可能收集到的依賴函數(shù)是不一樣的。

比如上文的computedObj對象,兩次收集得依賴就是不同的,因為第二次沒有計算函數(shù)的執(zhí)行。

2.設置了scheduler,再次觸發(fā)的時候,執(zhí)行函數(shù)就變成了scheduler。

比如上文收集的依賴函數(shù)c1。

到這里,effet應該有比較深入的認識了,下一篇再講講如何通過effec偵聽器來控制更新的時機,來實現(xiàn)組件更新。

以上就是vue源碼解析computed多次訪問會有死循環(huán)原理的詳細內容,更多關于vue computed多次訪問死循環(huán)的資料請關注腳本之家其它相關文章!

相關文章

最新評論