🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

Vue3 中的雙向鏈表依賴管理詳解與示例

image

在 Vue3 的響應式系統中,雙向鏈表是一個非常重要的數據結構。相比 Vue2 使用陣列來存放依賴,Vue3 選擇鏈表的原因在於效率更高,尤其是在頻繁收集和清理依賴時,鏈表可以顯著優化性能。本文將通過講解和示例代碼,幫助你理解這一點。


為什麼要用雙向鏈表

在響應式依賴收集過程中,Vue 需要完成兩件事:

  1. 收集依賴:當訪問響應式數據時,要記錄當前副作用函數(effect)。
  2. 清理依賴:當副作用函數重新運行或失效時,需要把它從依賴集合裡移除。

如果依賴集合使用陣列:

  • 刪除某個依賴需要遍歷整個陣列才能找到它,複雜度是 O(n)。
  • 當依賴數量多、更新頻繁時,性能就會下降。

使用雙向鏈表:

  • 刪除節點只需要修改前後兩個指針,複雜度是 O(1)。
  • 插入節點同樣是 O(1)。
  • 非常適合依賴頻繁增刪的場景。

雙向鏈表的基本結構

每個鏈表節點包含:

  • effect:保存副作用函數
  • prev:指向前一個節點
  • next:指向後一個節點

通過 prevnext,節點可以快速被插入或刪除。
示例:

A <-> B <-> C
刪除 B:
A.next = C
C.prev = A

代碼示例

下面的示例展示了如何通過雙向鏈表來管理依賴的添加、刪除和觸發。

// 鏈表節點:存儲副作用函數和前後指針
class EffectNode {
  constructor(effect) {
    this.effect = effect; // 要執行的副作用函數
    this.prev = null;     // 前一個節點
    this.next = null;     // 後一個節點
    this.dep = null;      // 當前節點所屬的依賴集合
  }
}

// 依賴集合(Dep):使用雙向鏈表存儲多個 effect
class Dep {
  constructor() {
    this.head = null; // 鏈表頭
    this.tail = null; // 鏈表尾
  }

  // 添加依賴:O(1),插入到鏈表尾部
  add(effect) {
    const node = new EffectNode(effect);
    node.dep = this;
    if (!this.head) {
      // 如果鏈表為空,頭尾都指向當前節點
      this.head = this.tail = node;
    } else {
      // 否則插入到尾部
      this.tail.next = node;
      node.prev = this.tail;
      this.tail = node;
    }
    return node; // 返回節點,方便以後刪除
  }

  // 刪除依賴:O(1),只需修改相鄰節點指針
  remove(node) {
    if (node.prev) node.prev.next = node.next;
    if (node.next) node.next.prev = node.prev;
    if (node === this.head) this.head = node.next;
    if (node === this.tail) this.tail = node.prev;
    // 清理引用,幫助垃圾回收
    node.prev = node.next = node.dep = null;
  }

  // 觸發依賴:遍歷鏈表,執行所有副作用函數
  trigger() {
    let cur = this.head;
    while (cur) {
      cur.effect();
      cur = cur.next;
    }
  }
}

// 模擬響應式數據
const state = { count: 0 };
// 每個屬性都可能有一個依賴集合,這裡用一個 dep 演示
const dep = new Dep();

// 註冊副作用函數,並收集依賴
function effect(fn) {
  const runner = () => fn();
  const node = dep.add(runner);
  runner(); // 立即執行一次
  return node; // 返回節點,方便後續刪除
}

// 使用:收集依賴
const node = effect(() => {
  console.log("副作用執行: count =", state.count);
});

// 修改數據時觸發依賴
state.count++;
dep.trigger(); // 輸出: 副作用執行: count = 1

// 刪除依賴,再次觸發時不會執行
dep.remove(node);
state.count++;
dep.trigger(); // 無輸出

輸出結果

副作用執行: count = 0
副作用執行: count = 1

在移除依賴後,再次修改數據時不會有輸出,說明鏈表刪除操作成功。


總結

  • Vue3 使用雙向鏈表來存儲依賴,是為了提升收集和清理的效率。
  • 相比陣列,鏈表的插入和刪除複雜度更低,尤其適合依賴數量多且頻繁變化的場景。
  • 通過示例可以看到,依賴的收集、觸發和清理都能高效完成。

這就是 Vue3 響應式系統比 Vue2 更快的一個重要原因。

本文部分內容借助 AI 輔助生成,並由作者整理審核。


原文出處:https://juejin.cn/post/7555815483686010921


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝18   💬9   ❤️5
678
🥈
我愛JS
📝4   💬14   ❤️7
252
🥉
御魂
💬1  
3
#5
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付