Vue3源碼reactivity響應式篇之computed計算屬性

概述

vue3中,computed函數用于表示計算屬性,有惰性求值、響應式追蹤依賴的特點。本文將介紹computed的實現原理以及其機制細節。

源碼解析

computed計算屬性和computed方法、ComputedRefImpl類以及refreshComputed方法有關。

computed方法

computed暴露給外部的就是computed方法,其源碼實現如下:

function computed(getterOrOptions, debugOptions, isSSR = false) {let getter;let setter;if (shared.isFunction(getterOrOptions)) {getter = getterOrOptions;} else {getter = getterOrOptions.get;setter = getterOrOptions.set;}const cRef = new ComputedRefImpl(getter, setter, isSSR);return cRef;
}

computed方法實現比較簡單,需要關注參數getterOrOptionsisSSRisSSR默認為false,它在服務端渲染會傳值為truedebugOptions用以在開發環境調試。

computed會先判斷getterOrOptions是否是函數,若是函數,則將其賦值給getter;當然getterOptions也可以是一個包含getset方法的對象。computed方法返回的是ComputedRefImpl實例,一般我們讀取計算屬性的值也是讀取它的返回值的.value

ComputedRefImpl

ComputedRefImpl用于構造一個計算屬性。

ComputedRefImpl的源碼實現如下:

class ComputedRefImpl {constructor(fn, setter, isSSR) {this.fn = getter; //計算函數this.setter = setter; // 設置函數(可選)this["_value"] = undefined; // 緩存的結果,計算屬性的值this.dep = new Dep(this); // 依賴收集器(收集依賴此計算屬性的副作用effect)this["__v_isRef"] = true; // 表示為ref類型this["__v_isReadonly"] = undefined; // 只讀標記this.deps = undefined; //當前計算屬性依賴的響應式集合對象鏈表頭this.depsTail = undefined; //鏈表尾this.flags = 16; //狀態標記this.globalVersion = globalVersion - 1;// 全局版本號,用于臟檢查this.isSSR = undefined; //服務端渲染標記this.next = undefined; //用于在effect鏈表中指向下一個節點this.effect = this; // 指向自身this["__V_isReadonly"] = !setter; //若無setter,則表示計算屬性是只讀的this.isSSR = isSSR;//ssr標記賦值}// 依賴變更調用notify() {this.flags |= 16;if (!(this.flags & 8) && activeSub !== this) {batch(this, true);return true;}}// 計算屬性值訪問器get value() {const link = this.dep.track()refreshComputed(this);if (link) {link.version = this.dep.version;}return this._value;}// 計算屬性值設置器set value(newValue) {if (this.setter) {this.setter(newValue)} else {warn("Write operation failed: computed value is readonly");}}
}

ComputedRefImpl中除了在構造器中定義了相關屬性外,就是包含兩個屬性訪問器函數和一個notify方法

notify

當計算屬性依賴的響應式值發生變化時,會調用notify方法.notify方法會先設置this.flags標志位的值,將其第4位置為1,表示有更新請求;然后判斷標志位的第3位是否為1并且當前激活訂閱(副作用)是不是自身,若條件滿足,則調用batch方法,將該計算屬性添加到更新隊列中,進行批量更新,最后返回true,表示更新已調度;若不滿足條件,則返回false,表示更新被跳過。

getter

getter屬性訪問器,會在讀取計算屬性的值時觸發。先進行依賴收集,追蹤當前正在運行的effect,然后調用refreshComputed方法進行有條件性的重新計算,若當前計算屬性被其他effect依賴,則更新依賴的版本,最后返回this._value

setter

setter屬性設置,一般情況下計算屬性只是只讀的,若this.setter方法存在,則可以調用該方法設置計算屬性的值。

refreshComputed方法

refreshComputed方法就是用于進行刷新計算屬性的值,滿足條件就重新進行計算,得到最新的計算屬性的值。

refreshComputed的源碼實現如下:

function refreshComputed(computed) {// 檢查更新條件if (computed.flags & 4 && !(computed.flags & 16)) {return;}// 清除pending狀態computed.flags & =-17;// 全局版本校驗 避免重復計算if (computed.globalVersion === globalVersion) {return;}computed.globalVersion = globalVersion;// 緩存有效性檢查 if (!computed.isSSR && computed.flags & 128 && (!computed.deps && !computed._dirty || !isDirty(computed))) {return;}// 標記計算狀態computed.flags |= 2;const dep = computed.dep;const prevSub = activeSub;const prevShouldTrack = shouldTrack;activeSub = computed;shouldTrack = true;try {// 依賴收集準備prepareDeps(computed);// 執行計算函數const value = computed.fn(computed._value);// 值變化檢測if (dep.version === 0 || hasChanged(value, computed._value)) {computed.flags |= 128; // 標記validcomputed._value = value;  dep.version++; // 觸發依賴更新}} catch (err) {dep.version++;throw err;} finally {activeSub = prevSub;shouldTrack = prevShouldTrack;cleanupDep(computed); // 清理過期依賴computed.flags &= -3; // 清除computing狀態}
}

refreshComputed方法會先檢查flags的值,若是被移除或者沒有更新請求,則直接返回;然后修改flags狀態,清除pending狀態;比較全局版本號和計算屬性的版本號,若二者一樣,則返回,避免是在計算屬性中修改了響應式屬性引起的重新計算;修改響應式的版本號;然后做緩存有效性的檢查;若是臟數據,則返回;再次標記flags狀態,表示是計算中;將當前effect計算屬性切換為activeSub,修改shouldTracktrue,調用prepareDeps進行依賴收集,然后執行計算屬性的fn,即傳入computed的參數函數,得到新的value,比較計算屬性的值是否發生改變,賦值this._value,并將其依賴dep的版本遞增,如此會觸發依賴該計算屬性的副作用effect更新;最后恢復activeSubshouldTrack,清理過期依賴以及清除計算狀態。

refreshComputed是計算屬性computed的核心方法,依據一些規則判斷需要執行fn,獲取最新的value以及觸發相關依賴。

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

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

相關文章

[嵌入式embed]Keil5燒錄后STM32不自動運行,復位才能運行

[嵌入式embed]Keil5燒錄后STM32不自動運行,復位才能運行Keil5-驗證“Reset and Run”功能是否生效參考文章Keil5-驗證“Reset and Run”功能是否生效 參考文章 Keil5燒錄后STM32不自動運行?必須復位才能啟動的終極解決方案

阿里云Qwen3系列模型部署微調評測

與阿里云一起輕松實現數智化讓算力成為公共服務:用大規模的通用計算,幫助客戶做從前不能做的事情,做從前做不到的規模。讓數據成為生產資料:用數據的實時在線,幫助客戶以數據為中心改變生產生活方式創造新的價值。模型…

北京魯成偉業 | 三屏加固筆記本電腦C156F3

在工業控制、應急指揮、測控及無人機作業等對設備穩定性與環境適應性要求較高的領域,一款性能均衡且堅固耐用的計算機往往能為工作效率提供有力支撐。三屏加固筆記本電腦C156F3便是針對這類需求設計的設備,憑借多方面的特性,可滿足不同場景下…

七彩氛圍燈芯片EH3A01RGB驅動芯片定時開關IC方案

?在現代智能家居和個性化照明領域,EH3A01-442A-A24F小夜燈定時芯片憑借其多功能、低功耗和靈活配置的特點,成為LED氛圍燈、小夜燈及便攜式照明方案的理想選擇。本文將深入解析該芯片的核心功能、電氣特性及應用場景,幫助開發者與用戶全面掌握…

Spring Boot 項目新增 Module 完整指南

1. 模塊化開發的重要性 在軟件開發中,隨著項目規模的不斷擴大,??模塊化設計??已成為提高代碼可維護性和可復用性的關鍵實踐。通過將大型項目拆分為多個獨立模塊,開發團隊可以??并行開發??不同功能組件,降低代碼耦合度&…

Git cherry-pick 與分支重置技術實現代碼健全性保障下的提交記錄精簡

代碼健全性保障:上市審查中的 Git 提交記錄整理方案(核心功能提交篩選流程) 一、背景與目的 我司正處于上市籌備階段,券商需對核心系統進行 Git 代碼審查,并基于提交記錄生成測試報告。由于原始提交記錄包含大量細節性…

前后端聯調時出現的一些問題記錄

服務器的ip沒有設置成所有ip都能訪問的,或防火墻沒開跨域問題(剛開始異源,有這個問題,主要是前端做一下配置代理,后端也可以配置跨域資源共享(CORS))Configuration public class Cor…

數字圖像處理-設計生成一個半球

1 實驗題目設計生成一個半球(matlab)。2 程序源代碼%Hemisphere clear,clc,close all %Sphere radius R1; %Set grid number n30; theta (-n:2:n)/n*pi; phi ([0,0:2:n])/n*pi/2; cosphi cos(phi); cosphi(1) 0; cosphi(end) 0; sintheta sin(thet…

mac M1上安裝windows虛擬機報錯

Parallels版本是18.0.02 mac:arm系統15.6.1 自動獲取windows11下載,安裝的時候報錯,藍屏,是因為安裝的版本不對,猜測原因應該是18.0.02不支持最新版的windows11,需要更新最新版的Parallels。 解決方案&am…

基于R語言機器學習方法在生態經濟學領域中的實踐技術應用

近年來,人工智能領域已經取得突破性進展,對經濟社會各個領域都產生了重大影響,結合了統計學、數據科學和計算機科學的機器學習是人工智能的主流方向之一,目前也在飛快的融入計量經濟學研究。表面上機器學習通常使用大數據&#xf…

第01章 初識MySQL與mysql8.0的安裝

初識 MySQL 文章目錄初識 MySQL引言一、數據庫基礎1.1 什么是數據庫1.2 表1.3 數據類型1.4 主鍵二、數據庫技術構成2.1 數據庫系統2.2 SQL 語言2.2.1 數據定義語言(DDL)2.2.2 數據操作語言(DML)2.2.3 數據查詢語言(DQL…

【數據結構基礎習題】-1- 數據結構基本操作

一、順序表和鏈表習題 1. 順序表就地逆置#include <stdio.h> // 定義順序表結構 #define MAXSIZE 100 typedef struct {int data[MAXSIZE];int length; } SqList; // 就地逆置順序表 void reverseList(SqList *L) {int i, temp;for (i 0; i < L->length / 2; i) {…

【Java實戰?】從0到1:Spring Boot Web開發與接口設計實戰

目錄一、Spring Boot Web 基礎配置1.1 Web 起步依賴&#xff08;spring-boot-starter-web 導入與核心組件&#xff09;1.2 內置服務器配置&#xff08;Tomcat 端口、線程池、連接超時設置&#xff09;1.3 靜態資源訪問&#xff08;靜態資源存放路徑、自定義資源映射&#xff09…

房屋安全鑒定機構評價

房屋安全鑒定機構評價&#xff1a;如何選擇專業可靠的檢測服務在建筑行業快速發展的今天&#xff0c;房屋安全鑒定已成為保障建筑安全、預防事故的重要環節。面對市場上眾多的房屋安全鑒定機構&#xff0c;如何科學評價并選擇一家專業可靠的服務提供方&#xff0c;是許多業主、…

【算法專題訓練】19、哈希表

1、哈希表基礎知識 以鍵值對的方式進行數據存儲優點&#xff1a;哈希表數據結構在插入、刪除或查找一個元素時&#xff0c;都只需要O(1)的時間 哈希表設計三要點&#xff1a; 為了快速確定一個元素在哈希表中的位置&#xff0c;可以使用一個數組&#xff0c;元素的位置為他的…

某光伏電力監控系統網絡安全監測項目:智能組網技術優化方案實踐

背景與挑戰隨著光伏電力行業的快速發展&#xff0c;光伏電站的規模和分布范圍日益擴大。電力監控系統作為光伏電站的核心平臺&#xff0c;其網絡安全直接關系到電力生產的穩定性與可靠性。然而&#xff0c;光伏場站通常分布在偏遠地區&#xff0c;網絡環境復雜&#xff0c;傳統…

GEE訓練教程:基于Landsat 8衛星影像識別并提取指定區域內無云覆蓋的區域多邊形,最終導出為矢量文件

簡介 本文使用Google Earth Engine平臺,通過Landsat 8衛星影像識別并提取指定區域內無云覆蓋的區域多邊形,最終導出為矢量文件。主要步驟包括:定義研究區域、創建云檢測算法、篩選高質量影像、將無云區域轉換為矢量多邊形,并進行可視化檢查和數據導出。 使用Google Earth…

UniApp 頁面通訊方案全解析:從 API 到狀態管理的最佳實踐

在 UniApp 跨端開發中&#xff0c;組件與頁面間的通訊是核心需求。無論是父子組件交互、跨頁面數據傳遞&#xff0c;還是全局狀態共享&#xff0c;選擇合適的通訊方案直接影響代碼的可維護性和性能。本文將系統對比 uni.$emit 系列 API、狀態管理庫&#xff08;Vuex/Pinia&…

【c++進階系列】:萬字詳解AVL樹(附源碼實現)

&#x1f525; 本文專欄&#xff1a;c &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 路在腳下延伸時&#xff0c;不必追問終點何在。你邁出的每一步&#xff0c;都在重新定義世界的邊界 ★★★ 本文前置知識&#xff1a; …

前端日志回撈系統的性能優化實踐|得物技術

一、前言在現代前端應用中&#xff0c;日志回撈系統是排查線上問題的重要工具。然而&#xff0c;傳統的日志系統往往面臨著包體積過大、存儲無限膨脹、性能影響用戶體驗等問題。本文將深入分析我們在dw/log和dw/log-upload兩個庫中實施的關鍵性能優化&#xff0c;以及改造過程中…