《Vue.js》閱讀之響應式數據與副作用函數

Vue.js

《Vue.js設計與實現》(霍春陽)

  • 適合:從零手寫Vue3響應式系統,大廠面試源碼題直接覆蓋。
  • 重點章節:第4章(響應式)、第5章(渲染器)、第8章(編譯器)

因為我第一周的任務就是響應式原理(Proxy vs defineProperty),手寫簡易reactive,所以我是從第四章開始學習的。

4.1 響應式數據與副作用函數

1、副作用函數

函數的執行會直接或間接影響其他函數的執行

比如:

01 function effect() {
02   document.body.innerText = 'hello vue3'
03 }

它的執行會使整個body的值都為hello vue3

2、響應式數據

01 const obj = { text: 'hello world' }
02 function effect() {
03   // effect 函數的執行會讀取 obj.text
04   document.body.innerText = obj.text
05 }

如上面的這一段代碼,我們希望當text發生變化的時候,effect會自動執行,這就是所謂的響應式數據

下面我們將會講到這是怎么實現的:

● 當副作用函數 effect 執行時,會觸發字段obj.text 的讀取操作;
● 當修改 obj.text 的值時,會觸發字段 obj.text的設置操作。
實現一個響應式的數據:攔截讀和寫兩個步驟,
讀的時候把effect函數放在一個容器里面
修改的時候就把這個effect函數釋放出來
攔截一個對象的讀取和設置操作:Proxy

  const data = { text: 'hello' }; // 定義數據對象const bucket = new Set(); // 設置一個容器用于存儲副作用函數const obj = new Proxy(data, {// 讀的時候攔截get(target, key) {bucket.add(effect); // 將當前活躍的副作用函數添加到容器return target[key]; // 返回屬性值},// 攔截設置操作set(target, key, newVal) {target[key] = newVal;bucket.forEach(fn => fn()); // 執行所有存儲的副作用函數return true;}});const  effect = () => {document.body.innerText = obj.text; // 副作用函數依賴于響應式數據};effect();setTimeout(() => {obj.text = "world"; // 修改數據,觸發響應式更新}, 1000); // 延遲1秒修改數據

繼續強化->我們現在硬編碼了effect,但是如果副作用函數的名字不叫effect的話,這段代碼就無法繼續工作了

所以我們要提供一個用來注冊副作用函數的機制

  // 用一個全局變量存儲被注冊的副作用函數let activeEffect;function effect (fn) {activeEffect = fn ; fn();}const bucket = new Set(); //設置一個容器const data = { text: 'world' }; // 初始化數據對象const obj = new Proxy(data , {//讀的時候攔截放在容器里面get( tartget, key ){if(activeEffect){bucket.add(activeEffect);}return tartget[key];//返回屬性值},set(target , key , newVal){// 攔截設置操作target[key] = newVal;bucket.forEach(fn => fn());return true;}})effect(() => {console.log('run');document.body.innerText = obj.text;})setTimeout(() => {obj.text = "hello"} , 1000)

當我們為obj添加新的屬性的時候

  setTimeout(() => {obj.notExist = "hello vue3"} , 1000)

匿名副作用函數內沒有讀取這個新的屬性的值,那么在1s之后不會起到寫操作(即放出桶里面的所有函數),但是我嘗試了一下,發現它執行了的。

我們為了解決這個問題,就要重新設計“桶”這個數據結構:讓它無論讀取的哪一個屬性都會將副作用函數收到桶里面,設置屬性的時候,無論設置的是哪一個屬性,也都會將副作用函數取出并執行。

  let activeEffect;function effect (fn) {activeEffect = fn; fn();}const bucket = new WeakMap();const data = { text: 'world' }; // 確保所有屬性都已定義const obj = new Proxy(data, {get(target, key){if(!activeEffect){return target[key];}// 根據tartget取來的depsMap,它是一個map類型let depsMap = bucket.get(target);// 如果不存在if(!depsMap){// 創建一個bucket.set(target, (depsMap = new Map()));}// 根據key取來的deps,它是一個set類型let deps = depsMap.get(key);// 如果不存在if(!deps){// 創建一個depsMap.set(key, (deps = new Set()));}deps.add(activeEffect); // 添加當前活躍的副作用函數return target[key];},set(target, key, newVal){target[key] = newVal;const depsMap = bucket.get(target);if(!depsMap){return;}const effects = depsMap.get(key);effects && effects.forEach(fn => fn()); // 只觸發與鍵相關的副作用函數}});effect(() => {console.log('run');document.body.innerText = obj.text;});setTimeout(() => {obj.text = "hello vue3"; // 修改已定義的屬性以觸發依賴}, 1000);

大家可以發現,我們引用了weakMap(它與map最大的不同就是它對key是弱引用,不影響垃圾回收器的工作,通常存儲只有當key所引用的對象存在時,才有價值的信息);

我們要解決的是屬性不存在時候的問題,那么

  • 在讀的時候判斷是否有這個屬性,沒有就創建一個,有的話就把函數放在桶里面。
  • 在修改的時候也是要判斷

最后,我們將一些函數進行封裝:

<script setup>let activeEffect;function effect (fn) {activeEffect = fn; fn();}const bucket = new WeakMap();const data = { text: 'world' }; // 確保所有屬性都已定義const obj = new Proxy(data, {get(target, key){track(target , key);return target[key];},set(target, key, newVal){target[key] = newVal;trigger(target , key , newVal);}});// 追蹤變化function track(target , key){if(!activeEffect){return target[key];}// 根據tartget取來的depsMap,它是一個map類型let depsMap = bucket.get(target);// 如果不存在if(!depsMap){// 創建一個bucket.set(target, (depsMap = new Map()));}// 根據key取來的deps,它是一個set類型let deps = depsMap.get(key);// 如果不存在if(!deps){// 創建一個depsMap.set(key, (deps = new Set()));}deps.add(activeEffect); // 添加當前活躍的副作用函數}// 觸發變化function trigger(target , key , newVal){const depsMap = bucket.get(target);if(!depsMap){return;}const effects = depsMap.get(key);effects && effects.forEach(fn => fn()); // 只觸發與鍵相關的副作用函數}effect(() => {console.log('run');document.body.innerText = obj.text;});setTimeout(() => {obj.text = "hello vue3"; // 修改已定義的屬性以觸發依賴}, 1000);
</script>

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

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

相關文章

數據處理專題(十三)

學會基本的圖像處理技術。? OpenCV 基礎 實踐&#xff1a;使用 OpenCV 進行圖像讀取、顯示和基本處理? 03 代碼示例 1. 導入必要的庫 import cv2import numpy as npimport matplotlib.pyplot as plt 2. 圖像讀取 # 讀取圖像image_path path_to_your_image.jpg # 替換…

springboot旅游小程序-計算機畢業設計源碼76696

目 錄 摘要 1 緒論 1.1研究背景與意義 1.2研究現狀 1.3論文結構與章節安排 2 基于微信小程序旅游網站系統分析 2.1 可行性分析 2.1.1 技術可行性分析 2.1.2 經濟可行性分析 2.1.3 法律可行性分析 2.2 系統功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系統…

P1874 快速求和

目錄 題目算法標簽: 動態規劃, 線性 d p dp dp思路代碼 題目 P1874 快速求和 算法標簽: 動態規劃, 線性 d p dp dp 思路 求的是最少組成 n n n的加法次數, 對于當前數字序列可以設計狀態表示 f [ i ] [ j ] f[i][j] f[i][j]表示考慮前 i i i個字符, 并且和是 j j j的所有方…

知名人工智能AI培訓公開課內訓課程培訓師培訓老師專家咨詢顧問唐興通AI在金融零售制造業醫藥服務業創新實踐應用

AI賦能未來工作&#xff1a;引爆效率與價值創造的實戰營 AI驅動的工作革命&#xff1a;從效率提升到價值共創 培訓時長&#xff1a; 本課程不僅是AI工具的操作指南&#xff0c;更是面向未來的工作方式升級羅盤。旨在幫助學員系統掌握AI&#xff08;特別是生成式AI/大語言模型…

Linux 內核參數

文章目錄 什么是內核參數參數種類配置方式1. 編譯內核時配置2. 內核啟動時配置3. 內核運行時配置4. 加載內核模塊時配置總結 什么是內核參數 內核參數是 Linux 系統中用于控制和調整內核行為的可配置選項。這些參數影響系統的性能、安全性和各種功能特性。 參數種類 大部分參…

pythonocc 拉伸特征

micromamba install -c conda-forge pythonocc-core opencascade.js安裝不起來&#xff0c;ai用pythonocc練個手 拉伸線框 線成面 from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Vec from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire f…

Vue.js 頁面切換空白與刷新 404 問題深度解析

在使用 Vue.js 開發單頁應用 (SPA) 的過程中&#xff0c;開發者經常會遇到兩個常見問題&#xff1a;頁面切換時出現短暫的空白屏幕&#xff0c;以及刷新頁面時返回 404 錯誤。這兩個問題不僅影響用戶體驗&#xff0c;還可能阻礙項目的正常上線。本文將深入探討這兩個問題的成因…

Go 語言 slice(切片) 的使用

序言 在許多開發語言中&#xff0c;動態數組是必不可少的一個組成部分。在實際的開發中很少會使用到數組&#xff0c;因為對于數組的大小大多數情況下我們是不能事先就確定好的&#xff0c;所以他不夠靈活。動態數組通過提供自動擴容的機制&#xff0c;極大地提升了開發效率。這…

Qt5.14.2 鏈接 MySQL 8.4 遇到的問題

問題一: "Plugin caching_sha2_password could not be loaded: 找不到指定的模塊。 Library path is caching_sha2_password.dll QMYSQL: Unable to connect" 解決方法: alter user root@localhost identified with mysql_native_password by root;問題二: ERR…

Docker 部署 - Crawl4AI 文檔 (v0.5.x)

Docker 部署 - Crawl4AI 文檔 (v0.5.x) 快速入門 &#x1f680; 拉取并運行基礎版本&#xff1a; # 不帶安全性的基本運行 docker pull unclecode/crawl4ai:basic docker run -p 11235:11235 unclecode/crawl4ai:basic# 帶有 API 安全性啟用的運行 docker run -p 11235:1123…

開發工具分享: Web前端編碼常用的在線編譯器

1.OneCompiler 工具網址&#xff1a;https://onecompiler.com/ OneCompiler支持60多種編程語言&#xff0c;在全球有超過1280萬用戶&#xff0c;讓開發者可以輕易實現代碼的編寫、運行和共享。 OneCompiler的線上調試功能完全免費&#xff0c;對編程語言的覆蓋也很全&#x…

Docker-配置私有倉庫(Harbor)

配置私有倉庫&#xff08;Harbor&#xff09; 一、環境準備安裝 Docker 三、安裝docker-compose四、準備Harbor五、配置證書六、部署配置Harbor七、配置啟動服務八、定制本地倉庫九、測試本地倉庫 Harbor(港灣)&#xff0c;是一個用于 存儲 和 分發 Docker 鏡像的企業級 Regi…

關于高并發GIS數據處理的一點經驗分享

1、背景介紹 筆者過去幾年在參與某個大型央企的項目開發過程中,遇到了十分棘手的難題。其與我們平常接觸的項目性質完全不同。在一般的項目中,客戶一般只要求我們能夠通過桌面軟件對原始數據進行加工處理,將各類地理信息數據加工處理成地圖/場景和工作空間,然后再將工作空…

使用 DMM 測試 TDR

TDR&#xff08;時域反射計&#xff09;可能是實驗室中上升時間最快的儀器&#xff0c;但您可以使用直流歐姆表測試其準確性。 TDR 測量什么 在所有高速通道中&#xff0c;反射都很糟糕。我們嘗試設計一個通道來減少反射&#xff0c;這些反射都會導致符號間干擾 &#xff08;…

可視化圖解算法37:序列化二叉樹-II

1. 題目 描述 請實現兩個函數&#xff0c;分別用來序列化和反序列化二叉樹&#xff0c;不對序列化之后的字符串進行約束&#xff0c;但要求能夠根據序列化之后的字符串重新構造出一棵與原二叉樹相同的樹。 二叉樹的序列化(Serialize)是指&#xff1a;把一棵二叉樹按照某種遍…

【Python】Python常用數據類型詳解

Python常用數據類型詳解:增刪改查全掌握 Python作為一門簡潔高效的編程語言,其豐富的數據類型是構建程序的基礎。本文將詳細介紹數字、字符串、列表、元組、字典、集合這六種核心數據類型的特點及增刪改查操作,并附代碼示例,助你全面掌握數據操作技巧。 一、數字(Number)…

模板引用、組件基礎

#### 組件基礎 1. 定義和使用簡單組件 - ![alt text](./img/image-2.png) vue <!-- 在App.vue里 --> <script setup>import HelloWorld from ./components/HelloWorld.vue </script> <template><HelloWorld></HelloWorld></temp…

深入探索 RKNN 模型轉換之旅

在人工智能蓬勃發展的當下&#xff0c;邊緣計算領域的應用愈發廣泛。瑞芯微的 RKNN 技術在這一領域大放異彩&#xff0c;它能讓深度學習模型在其芯片平臺上高效運行。而在整個應用流程中&#xff0c;模型轉換是極為關鍵的一環&#xff0c;今天就讓我們一同深入這個神奇的 RKNN …

iframe嵌套網站的安全機制實現

背景&#xff1a; 公司內部有一套系統A部署在內網&#xff0c;這套系統嵌套了B網站&#xff08;也是內網&#xff09;&#xff0c;只有內網才能訪問。現在需要將這個A系統暴露到公網。B系統的安全策略比較低&#xff0c;想快速上線并提高B系統的安全性。 通過 Nginx 代理層 設置…

青少年編程與數學 02-019 Rust 編程基礎 08課題、字面量、運算符和表達式

青少年編程與數學 02-019 Rust 編程基礎 08課題、字面量、運算符和表達式 一、字面量1. 字面量的分類1.1 整數字面量1.2 浮點數字面量1.3 字符字面量1.4 字符串字面量1.5 布爾字面量1.6 字節數組字面量 2. 字面量的類型推斷3. 字面量的用途4. 字面量的限制字面量總結 二、運算符…