iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Vue.js

從零到一打造 Vue3 響應式系統系列 第 12

Day 12 - Effect :多重依賴之指數觸發重現

  • 分享至 

  • xImage
  •  

banner

昨天我們解決了單一依賴所導致的指數增長問題。然而,在真實的開發場景中,一個 effect 函式往往需要依賴多個響應式變數,現在我們試著新增多個依賴,在範例中加入第二個響應式變數 count,並讓 effect 同時依賴 flagcount。按鈕的點擊事件只會修改 count 的值。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <style>
      body {
        padding: 150px;
      }
    </style>
  </head>
  <body>
    <button id="btn">按钮</button>
    <script type="module">
      import { ref, effect } from '../dist/reactivity.esm.js'

      const flag = ref(true)
      const count = ref(0)

      effect(() => {
        flag.value
        count.value
        console.count('effect')
      })

      btn.onclick = () => {
        count.value++
      }
    </script>
  </body>
</html>

day12-01

effect 函式同時依賴 flagcount 兩個響應式變數後,點擊按鈕觸發更新時,問題又回來了,依賴收集再次出現了指數級的增長,為什麼會這樣?

初始化

day12-02

頁面第一次載入,effect 執行一次。它依序讀取 flag.valuecount.value,觸發兩次依賴收集。

  • flag 透過 Link1effect 關聯。
  • count 透過 Link2effect 關聯。
  • effect 自己的 deps 鏈表也記錄Link1 -> Link2

到目前為止,都沒什麼問題。

點擊按鈕執行第一次

day12-03

當按鈕點擊,count.value++ 觸發更新,effectrun() 方法被呼叫。

  • 執行 run()depsTail = undefined
  • this.deps 仍然指向 Link1

(deps && !depsTail) 的狀態,就是我們用來判斷是否「正在重新執行」的關鍵點。

day12-04

  • 讀取 flag.value,觸發第一次 link()
    • effect 函式體重新執行,先讀取 flag.value,觸發 link(flag, effect)
    • link() 開始判斷:
      • 條件:depsTail = undefined 、頭節點sub.deps 存在 (sub.deps && !sub.depsTail) 成立。
      • 接著檢查 sub.deps.dep === dep ( Link1dep 是否為 flag),成立。
    • 複用成功,depsTail 移到 flag 的 link。

day12-05

  • 讀取 count.value,觸發第二次 link()
    • effect 繼續執行,讀取 count.value,觸發 link(count, effect)
    • link() 開始判斷:
      • (sub.deps && !sub.depsTail) 不成立,因為剛剛 depsTail 移到 flag 的 link。
      • 複用檢查直接失敗,建立了一個全新的 Link3 節點,並且移動指針。

day12-06

執行完,flag 的依賴 (Link1) 被正確複用,但 count 的依賴被重複新增了節點 (Link2 存在,又新增了 Link3)。

導致下一次點擊按鈕,propagate 就會觸發 effect 執行兩次(透過 Link2Link3),因此指數增長。

問題分析:為何只有第一個依賴被正確複用?

邏輯問題:

  • 我們只檢查了 sub.deps(頭節點),它永遠只拿 effect 依賴鏈表的第一個節點來比較,導致只有第一個依賴能被複用。
  • 一旦第一個依賴複用成功,depsTail 就被賦值,後續的依賴檢查全部失敗。

今天我們ㄓ透過圖解,一步步追蹤了內部依賴鏈表的情況。分析後可以知道,問題的根源在於現有的節點複用邏輯存在漏洞:它只會檢查並比對依賴鏈表的第一個節點 (sub.deps)。

明天我們將基於這次的問題解析結果,來實作解決方案。


同步更新《嘿,日安!》技術部落格


上一篇
Day 11 - Effect:Link 節點的複用實作
下一篇
Day 13 - Effect:多重依賴之節點復用解方
系列文
從零到一打造 Vue3 響應式系統13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言