Vue 3.0中響應式依賴和更新

響應式依賴和更新是Vue 3.0中最重要的機制,其核心代碼如下,本文將結合代碼對這個設計機制作出一些解釋。

// 全局依賴存儲:WeakMap<target, Map<key, Set<effect>>>
const targetMap = new WeakMap();// 當前活動的副作用函數(如組件的渲染函數)
let activeEffect = null;// 響應式入口函數
function reactive(target) {return createReactiveObject(target, mutableHandlers);
}// 創建響應式代理對象
function createReactiveObject(target, handlers) {if (typeof target !== 'object' || target === null) {return target; // 非對象直接返回}return new Proxy(target, handlers);
}// Proxy 攔截器配置
const mutableHandlers = {get(target, key, receiver) {track(target, key); // 依賴收集const res = Reflect.get(target, key, receiver);if (typeof res === 'object' && res !== null) {return reactive(res); // 深度響應式}return res;},set(target, key, value, receiver) {const oldValue = target[key];const result = Reflect.set(target, key, value, receiver);if (oldValue !== value) {trigger(target, key); // 觸發更新}return result;},// 其他攔截器(deleteProperty/has/ownKeys 等省略)
};// 依賴收集:建立 target.key → effect 的映射
function track(target, key) {if (!activeEffect) return; // 無活動 effect 則退出let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = new Set()));}if (!dep.has(activeEffect)) {dep.add(activeEffect); // 添加 effect 到依賴集合activeEffect.deps.push(dep); // 反向關聯(用于清理)}
}// 觸發更新:執行 target.key 的所有依賴 effect
function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;const effects = new Set();const dep = depsMap.get(key);if (dep) {dep.forEach(effect => effects.add(effect));}effects.forEach(effect => effect()); // 重新執行副作用函數
}// 副作用函數封裝(示例)
function effect(fn) {const effectFn = () => {activeEffect = effectFn;fn();activeEffect = null;};effectFn.deps = []; // 存儲所有關聯的 dep 集合effectFn();
}

1. 核心數據結構:targetMap

類型:WeakMap<Object, Map<string, Set<Effect>>>

作用:全局存儲所有響應式對象的依賴關系。

鍵:被代理的原始對象Object。

值:一個?Map,其鍵是對象的屬性名,值是一個?Set,存儲了與該屬性相關的所有副作用函數,如組件的渲染函數。

2.?track 函數:依賴收集

觸發時機:當訪問響應式對象的某個屬性時,即觸發get操作。

核心流程:

1. 獲取當前活動的副作用函數:activeEffect?指向當前正在執行的副作用函數,例如組件渲染函數或?watch?回調;

2. 初始化依賴關系:從?targetMap?中獲取目標對象?target?對應的?depsMap,若不存在,則新建一個?Map。從?depsMap?中獲取屬性?key?對應的依賴集合?dep,若不存在,則新建一個?Set;

3. 建立雙向關聯:將?activeEffect?添加到?dep 中,表示該屬性依賴此副作用函數。將?dep?添加到?activeEffect.deps中,用于后續清理無效依賴,避免內存泄漏;

const obj = reactive({ count: 0 });
effect(() => console.log(obj.count));  
// 執行 effect 時,`activeEffect` 指向該函數
// 訪問 obj.count 時觸發 track,將 effect 函數添加到 count 的依賴集合中。

3. trigger 函數:觸發更新

觸發時機:當修改響應式對象的屬性時 ,即觸發set 操作。

核心流程:

1. 獲取目標對象的依賴集合:從?targetMap?中獲取?target?對應的?depsMap;

2. 收集所有相關副作用函數:從?depsMap?中獲取屬性?key?對應的?dep,即該屬性的所有依賴函數。將dep中的所有?effect?添加到一個臨時集合?effects?中;

3. 執行副作用函數:遍歷?effects,依次執行每個?effect,觸發視圖更新或回調邏輯;?

obj.count++;  // 修改 count 時觸發 trigger,執行所有依賴 count 的 effect。

4. 關鍵設計細節

1. WeakMap?的作用:鍵是弱引用,當目標對象?target?不再被引用時,targetMap?中對應的條目會被自動垃圾回收,避免內存泄漏;?

2. activeEffect?的管理:通過?effect?函數或組件渲染過程,將當前運行的副作用函數賦值給?activeEffect。執行完畢后,activeEffect?會被重置為?null,確保依賴收集的準確性;?

3. 雙向依賴關系:effect.deps?存儲了所有與該副作用函數相關的依賴集合dep。當副作用函數被銷毀時,可以通過遍歷?effect.deps?從所有?dep?中移除該函數,避免無效更新;?

4. 性能優化:使用?Set?存儲依賴函數,避免重復添加。觸發更新時,通過臨時集合?effects?確保每個?effect?只執行一次,避免循環觸發;?

5. 總結

依賴收集(Track):通過?track?函數,在屬性被訪問時記錄當前活動的副作用函數,建立屬性與副作用函數的關聯。

觸發更新(Trigger):通過?trigger?函數,在屬性被修改時找到所有相關副作用函數并執行,實現數據變化到視圖更新的響應式機制。

全局依賴關系:targetMap?作為核心數據結構,通過?WeakMap?和嵌套的?Map/Set,高效管理對象、屬性和副作用函數之間的映射關系。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80628.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80628.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80628.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一、內存調優

一、內存調優 什么是內存泄漏 監控Java內存的常用工具 內存泄露的常見場景 內存泄露的解決方案 內存泄露與內存溢出的區別 內存泄露&#xff1a;在Java中如果不再使用一個對象&#xff0c;但是該對象依然在GC ROOT的引用鏈上&#xff0c;這個對象就不會被垃圾回收器回收&…

Linux /etc/rc.d/init.d/

在傳統的 SysV init 系統中&#xff0c;服務啟動腳本通常位于 /etc/rc.d/init.d/ 目錄下。這些腳本可以直接執行以啟動、停止或重啟服務&#xff0c;并且可以接受參數如 start, stop, status 等。 如果你想知道位于 /etc/rc.d/init.d/ 目錄下的某個腳本文件實際上指向哪里,如果…

S7 200 smart連接Profinet轉ModbusTCP網關與西門子1200PLC配置案例

控制要求&#xff1a;使用MODBUSTCP通信進行兩臺PLC之間的數據交換&#xff0c;由于改造現場不能改動程序&#xff0c;只留出了對應的IQ地址。于是客戶決定使用網關進行通訊把數據傳到plc。 1、讀取服務器端40001~40005地址中的數據&#xff0c;放入到VW200~VW208中&#xff1…

打破傳統倉庫管理困局:WMS如何重構出入庫全流程

引言 在制造業與零售業高速發展的今天&#xff0c;倉庫管理仍普遍面臨效率低、錯發漏發頻發、庫存數據滯后等痛點。人工登記導致30%的錯單率&#xff0c;貨位混亂讓揀貨耗時增加50%&#xff0c;而賬實不符引發的二次采購成本更吞噬著企業利潤。如何突破傳統管理桎梏&#xff1…

Text2SQL在Spark NLP中的實現與應用:將自然語言問題轉換為SQL查詢的技術解析

概述 SQL 仍然是當前行業中最受歡迎的技能之一 免責聲明&#xff1a;Spark NLP 中的 Text2SQL 注釋器在 v3.x&#xff08;2021 年 3 月&#xff09;中已被棄用&#xff0c;不再使用。如果您想測試該模塊&#xff0c;請使用 Spark NLP for Healthcare 的早期版本。 自新千年伊…

微服務項目->在線oj系統(Java版 - 5)

相信自己,終會成功 微服務代碼: lyyy-oj: 微服務 目錄 C端代碼 用戶題目接口 修改后用戶提交代碼(應用版) 用戶提交題目判題結果 代碼沙箱 1. 代碼沙箱的核心功能 2. 常見的代碼沙箱實現方式 3. 代碼沙箱的關鍵問題與解決方案 4. 你的代碼如何與沙箱交互&#xff1f; …

Vue3 Element Plus 中el-table-column索引使用問題

在 Element Plus 的 el-table 組件中&#xff0c;使用 scope.index 是不準確的。正確的索引屬性應該是 scope.$index。你的代碼需要調整為&#xff1a; vue 復制 下載 <el-button type"primary" size"default" text click"onModifyClick(scope…

Ubuntu20.04下使用dpkg方式安裝WPS后,將WPS改為中文界面方法

Ubuntu20.04下使用dpkg方式安裝WPS后&#xff0c;將WPS改為中文界面方法 說明方法 說明 Ubuntu20.04下使用dpkg方式安裝WPS后&#xff0c;打開WPS后&#xff0c;發現界面是英文的&#xff0c;如有需要可以按照下面的方法將其改為中文界面。 方法 cd /opt/kingsoft/wps-offic…

【??HTTPS基礎概念與原理?】??HTTPS vs HTTP:為什么現代網站必須用HTTPS?

以下是關于 HTTPS vs HTTP 的詳細對比分析&#xff0c;涵蓋安全性、性能差異及SEO影響&#xff0c;幫助您全面理解為何現代網站必須采用HTTPS&#xff1a; 一、安全性對比&#xff1a;HTTPS 如何解決 HTTP 的致命缺陷 1. HTTP 的安全隱患 ? 明文傳輸&#xff1a;HTTP 數據以明…

算法刷題(Java與Python)1.二分查找

目錄 二分查找 思路 總體 細節 問題一&#xff0c;為什么循環的條件是left<right ,為什么要有等號呢 問題二&#xff0c;為什么中間值是left (right - left) / 2 問題三&#xff0c;為什么最后返回的是左邊的值呢 情況 1&#xff1a;target 存在于數組中 情況 2&a…

芯片生態鏈深度解析(二):基礎設備篇——人類精密制造的“巔峰對決”

【開篇&#xff1a;設備——芯片工業的“劍與盾”】 當ASML的EUV光刻機以每秒5萬次激光脈沖在硅片上雕刻出0.13nm精度的電路&#xff08;相當于在月球表面精準定位一枚二維碼&#xff09;&#xff0c;當國產28nm光刻機在華虹產線實現“從0到1”的突破&#xff0c;這場精密制造…

MongoTemplate 基礎使用幫助手冊

前言 MongoDB 是一種流行的 NoSQL 數據庫&#xff0c;適合存儲大量的非結構化數據。MongoTemplate 是 Spring Data MongoDB 中的一個核心組件&#xff0c;它提供了一組豐富的 API 來與 MongoDB 進行交互。它封裝了許多常見的數據庫操作&#xff0c;使開發者能夠輕松執行 CRUD 操…

psotgresql18 源碼編譯安裝

環境&#xff1a; 系統&#xff1a;centos7.9 數據庫&#xff1a;postgresql18beta1 #PostgreSQL 18 已轉向 DocBook XML 構建體系&#xff08;SGML 未來將被棄用&#xff09;。需要安裝 XML 工具鏈&#xff0c;如下&#xff1a; yum install -y docbook5-style-xsl libxsl…

C++編程起步項目

員工信息管理系統 需求 Employee.h #pragma once#include<iostream> #include<string>using namespace std;class Employee { public:int id; // 編號string name; // 姓名string position; // 崗位int deptId; // 部門編號Employee();Employee(int id, string n…

Linux的MySQL頭文件和找不到頭文件問題解決

頭文件 #include <iostream> #include <mysql_driver.h> #include <mysql_connection.h> #include <cppconn/statement.h> #include <cppconn/resultset.h> #include <cppconn/prepared_statement.h> #include <cppconn/exception.h&g…

[ linux-系統 ] 命令行參數 | 環境變量

命令行參數 命令行參數是指用戶在啟動程序時通過命令行傳遞給程序的參數。這些參數可以用于控制程序的行為、傳遞輸入數據或配置選項。 在 C/C 中&#xff0c;命令行參數通過 main 函數的參數傳遞 命令行參數列表 argc:參數的個數 argv[]&#xff1a;參數的清單 為什么要…

新書速覽|鴻蒙HarmonyOS NEXT開發之路 卷2:從入門到應用篇

《鴻蒙HarmonyOS NEXT開發之路 卷2&#xff1a;從入門到應用篇》 01 本書內容 《鴻蒙HarmonyOS NEXT開發之路 卷2&#xff1a;從入門到應用篇》是一本深度聚焦HarmonyOS NEXT應用開發的全方位指導書&#xff0c;內容遵循由淺入深的原則展開。全書分為基礎知識、應用開發進階和…

經典密碼學和現代密碼學的結構及其主要區別(1)凱撒密碼——附py代碼

密碼學是一門通過使用代碼和密碼來保護信息的藝術與科學&#xff0c;其歷史可以追溯到數千年前。古典密碼學代表了這一古老學科早期的篇章。早在計算機和現代加密算法出現之前&#xff0c;歷史上的各個文明就依靠巧妙的方法來保護機密、安全通信以及獲取戰略優勢。 古典密碼學…

Python60日基礎學習打卡D30

回顧&#xff1a; 導入官方庫的三種手段導入自定義庫/模塊的方式導入庫/模塊的核心邏輯&#xff1a;找到根目錄&#xff08;python解釋器的目錄和終端的目錄不一致&#xff09; # 直接導入 from random import randint print(randint(1, 10)) # 導入自定義庫 import module m…

Linux利用多線程和線程同步實現一個簡單的聊天服務器

1. 概述 本文實現一個基于TCP/IP的簡單多人聊天室程序。它包含一個服務器端和一個客戶端&#xff1a;服務器能夠接收多個客戶端的連接&#xff0c;并將任何一個客戶端發來的消息廣播給所有其他連接的客戶端&#xff1b;客戶端則可以連接到服務器&#xff0c;發送消息并接收來自…