vue響應式原理

vue響應式原理

initState

new Vue() => _init() => initState:

function initState (vm: Component) {vm._watchers = []const opts = vm.$optionsif (opts.props) initProps(vm, opts.props)if (opts.methods) initMethods(vm, opts.methods)if (opts.data) {initData(vm)} else {observe(vm._data = {}, true /* asRootData */)}if (opts.computed) initComputed(vm, opts.computed)if (opts.watch && opts.watch !== nativeWatch) {initWatch(vm, opts.watch)}
}

判斷該vue實例是否存在propsmethodsdatacomputedwatch進行調用相應的初始化函數

initProps與initData

主要工作是調用defineProperty給屬性分別掛載get(觸發該鉤子時,會將當前屬性的dep實例推入當前的Dep.target也就是當前watcher的deps中即它訂閱的依賴,Dep.target下文會講到。且該dep實例也會將當前watcher即觀察者推入其subs數組中)、set方法(通知該依賴subs中所有的觀察者watcher去調用他們的update方法)。

initComputed

它的作用是將computed對象中所有的屬性遍歷,并給該屬性new一個computed watcher(計算屬性中定義了個dep依賴,給需要使用該計算屬性的watcher訂閱)。也會通過調用defineProperty給computed掛載get(get方法)、set方法(set方法會判斷是否傳入,如果沒傳入會設置成noop空函數)
computed屬性的get方法是下面函數的返回值函數

function createComputedGetter (key) {return function computedGetter () {const watcher = this._computedWatchers && this._computedWatchers[key]if (watcher) {watcher.depend()return watcher.evaluate()}}
}

注意其中的watcher.depend(),該方法讓用到該屬性的watcher觀察者訂閱該watcher中的依賴,且該計算屬性watcher會將訂閱它的watcher推入他的subs中(當計算屬性值改變的時候,通知訂閱他的watcher觀察者)
watcher.evaluate(),該方法是通過調用watcher的get方法(其中需要注意的是watcher的get方法會調用pushTarget將之前的Dep.target實例入棧,并設置Dep.target為該computed watcher,被該計算屬性依賴的響應式屬性會將該computed watcher推入其subs中,所以當被依賴的響應式屬性改變時,會通知訂閱他的computed watcher,computed watcher 再通知訂閱該計算屬性的watcher調用update方法),get方法中調用計算屬性key綁定的handler函數計算出值。

initWatch

該watcher 為user watcher(開發人員自己在組件中自定義的)。
initWatch的作用是遍歷watch中的屬性,并對每個watch監聽的屬性調用定義的$watch

Vue.prototype.$watch = function (expOrFn: string | Function,cb: any,options?: Object): Function {const vm: Component = thisif (isPlainObject(cb)) {return createWatcher(vm, expOrFn, cb, options)}options = options || {}options.user = true // 代表該watcher是用戶自定義watcherconst watcher = new Watcher(vm, expOrFn, cb, options)if (options.immediate) {cb.call(vm, watcher.value)}return function unwatchFn () {watcher.teardown()}}

代碼中調用new Watcher的時候,也會同render watcher一樣,執行下watcher的get方法,調用pushTarget將當前user watcher賦值給Dep.target,get()中value = this.getter.call(vm, vm)這個語句會觸發該自定義watcher監聽的響應式屬性的get方法,并將當前的user watcher推入該屬性依賴的subs中,所以當user watcher監聽的屬性set觸發后,通知訂閱該依賴的watcher去觸發update,也就是觸發該watch綁定的key對應的handler。然后就是調用popTarget出棧并賦值給Dep.target。

$mount

initState初始化工作大致到這里過,接下去會執行$mount開始渲染工作
$mount主要工作:new了一個渲染Watcher,并將updateCompent作為callback傳遞進去并執行

updateComponent = () => {vm._update(vm._render(), hydrating)}
new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted) {callHook(vm, 'beforeUpdate')}}}, true /* isRenderWatcher */)

三種watcher中new Watcher的時候,只有computed watcher不會一開始就執行它的get()方法。$mount里面new的這個render watcher會調用get()方法,調用pushTarget將當前render watcher賦值給Dep.target。接下去重頭戲來了,調用updateComponent,該方法會執行vm._update(vm._render(), hydrating),其中render函數會觸發html中使用到的響應式屬性的get鉤子。get鉤子會讓該響應式屬性的依賴實例dep將當前的render watcher推入其subs數組中,所以當依賴的響應式屬性改變之后,會遍歷subs通知訂閱它的watcher去調用update()。

例子

可能大家對watcher和dep調來調去一頭霧水,我講個實例

<div id="app"><div>{{a}}</div><div>{{b}}</div></div>
new Vue({el: "#app",data() {return {a:1,}},computed:{b() {return a+1}},
})

我直接從渲染開始講,只講跟dep跟watcher有關的
$mount:new一個渲染watcher(watcher的get方法中會將渲染watcher賦值給Dep.target)的時候會觸發 vm._update(vm._render(), hydrating),render的時候會獲取html中用到的響應式屬性,上面例子中先用到了a,這時會觸發a的get鉤子,其中dep.depend()會將當前的渲染watcher推入到a屬性的dep的subs數組中。
接下去繼續執行,訪問到b(b是計算屬性的值),會觸發計算屬性的get方法。計算屬性的get方法是調用createComputedGetter函數后的返回函數computedGettercomputedGetter函數中會執行watcher.depend()。Watcher的depend方法是專門留給computed watcher使用的。剛才上面說過了除了computed watcher,其他兩種watcher在new 完之后都會執行他們的get方法,那么computed watcher在new完之后干嘛呢,它會new一個dep。回到剛才說的專門為computed watcher開設的方法watcher.depend(),他的作用是執行this.dep.depend()(computed watcher定義的dep就是在這里使用到的)。this.dep.depend()會讓當前的渲染watcher訂閱該計算屬性依賴,該計算屬性也會將渲染watcher推入到它自己的subs([render watcher])中,當計算屬性的值修改之后會通知subs中的watcher調用update(),所以計算屬性值變了頁面能刷新。回到前面說的觸發b計算屬性的get鉤子那里,get鉤子最后會執行watcher.evaluate(),watcher.evaluate()會執行computed watcher的get()方法。這時候重點來了,會將Dep.target(render watcher)推入targetStack棧中(存入之后以便待會兒取出繼續用),然后將這個計算屬性的computed watcher賦值給Dep.target。get方法中value = this.getter.call(vm, vm),會執行computed屬性綁定的handler。如上面例子中return a + 1。使用了a那么就一定會觸發a的get鉤子,get鉤子又會調用dep.depend(),dep.depend()會讓computed watcher將dep存入它的deps數組中,a的dep會將當前的Dep.target(computed watcher)存入其subs數組中,當前例子中a的subs中就會是[render watcher,computed watcher],所以a值變化會遍歷a的subs中的watcher調用update()方法,html中用到的a會刷新,計算屬性watcher調用update()方法會通知他自己的subs([render watcher])中render watcher去調用update方法,html中用到的計算屬性b才會刷新dom(這里提個醒,我只是粗略的講,計算屬性依賴的屬性變化后他不一定會觸發更新,他會比較計算完之后的值是否變化)。computed watcher的get()方法最后會調用popTarget(),將之前存入render watcher出棧并賦值給Dep.target,這時候我例子中targetStack就變成空數組了。render watcher的get方法執行到最后也會出棧,這時候會將Dep.target賦值會空。

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

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

相關文章

Oracle數據庫管理與開發pdf

下載地址&#xff1a;網盤下載基本介紹編輯內容簡介Oracle是一個適合于大中型企事業的數據庫管理系統&#xff0c;在銀行、電信、移動通信、航空、保險、金融、氣象、鐵路、跨國公司和電子商務等諸多領域得到了廣泛的應用。據統計&#xff0c;在所有數據庫管理系統中&#xff0…

DVS/DVR區別

一、DVS &#xff08;Digital Video Server&#xff09;網絡視頻服務器的簡稱。DVS(網絡視頻服務器)的原理網絡視頻服務器主要實現模擬視音頻信號的IP 化。經數字化的視音頻信號MPEG-4 視頻壓縮算法和G.729/ADPCM 音頻壓縮算法進行壓縮編碼&#xff0c;然后通過IP 網將低碼率的…

自動對焦方法學習

實現自動對焦的方法有很多種,可以根據不同的工作原理,將自動對焦技術分成不同種類。 按照系統是否自帶信號發射系統,可以分為主動式與被動式兩種類型。 主動式對焦方法是由成像系統中的發射裝置發出信號,然后再由接收裝置接收從被攝景物所反射回來的反饋信號并利用通過計算…

微粒化運營:升級內容產業消費體驗(附視頻版)

那些最受歡迎的內容平臺做對了什么&#xff1f; Facebook和Google是全球互聯網廣告產業中最早開始微粒化運營的代表&#xff0c;Google的互聯網精準廣告的思路與微粒化運營是完全相同的&#xff0c;這兩家公司也因此獲得了全球超過20%的互聯網廣告的收入。 以Facebook為例&…

mycat讀寫分離

只需要讀寫分離的功能&#xff0c;分庫分表的都不需要。 涉及到的配置文件&#xff1a; 1.conf/server.xml 主要配置的是mycat的用戶名和密碼&#xff0c;mycat的用戶名和密碼和mysql的用戶名密碼是分開的&#xff0c;應用連接mycat就用這個用戶名和密碼。 <?xml version&q…

chisel快速入門(一)

一、概述 Chisel&#xff08;Constructing Hardware In a Scala Embedded Language&#xff09;是一種嵌入在高級編程語言Scala的硬件構建語言。Chisel實際上只是一些特殊的類定義&#xff0c;預定義對象的集合&#xff0c;使用Scala的用法&#xff0c;所以在寫Chisel程序時實際…

DVS/DVR常見的監控名詞

英文名詞 說明BNC 全稱Bayonet Nut Connector&#xff0c;一種用于同軸電纜的連接器DHCP 動態主機配置協議&#xff0c;用于動態地指派配置信息DNS 域名系統&#xff0c;以用戶友好的方式將名字轉換為…

導出數據生成excel

前臺&#xff1a; <asp:Button ID"btnMoney" runat"server" Text"經費使用總結表" CssClass"admin_cx marginleft" Height"25" OnClick"btnMoney_Click" /> 后臺&#xff1a; protected void btnMoney_Cli…

U盤基本處理,U盤與移動固態硬盤

一、辨別 USB2.0 和 USB3.0 1、從USB外觀上來看&#xff0c;USB2.0通常是白色或黑色&#xff0c;而USB3.0則改觀為“高大上”的藍色接口。 目前&#xff0c;部分筆記本電腦USB接口&#xff0c;已同時提供對USB2.0及USB3.0的支持&#xff0c;我們可以通過接口顏色來區別。 2、從…

UWP_小說在線閱讀器:功能要求與技術要求

注&#xff1a;2017年2月23日正式提上日程 學了WP開發也有一年了&#xff0c;也沒做過什么軟件的。17年進發UWP&#xff0c;鍛煉自己一下。做一個開源的小說閱讀器吧。 既然開發一個軟件。所以要設計一下吧。 功能要求&#xff1a; 可能要用到的技術&#xff0c;這個嗎&#xf…

chisel快速入門(二)

上一篇見此&#xff1a; chisel快速入門&#xff08;一&#xff09;_滄海一升的博客-CSDN博客簡單介紹了chisel&#xff0c;使硬件開發者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121415341 十、運行和測試 現在我們已經定義了模塊&#xff0c;…

【WPF】設置TextBox內容為空時的提示文字

原文:【WPF】設置TextBox內容為空時的提示文字<TextBox Width"150" Margin"5"><TextBox.Resources><VisualBrush x:Key"HintText" TileMode"None" Opacity"0.5" Stretch"None" AlignmentX"Le…

視頻矩陣

視頻矩陣&#xff0c;就將視頻圖像從任意一個輸入通道切換到任意一個輸出通道顯示。一般來講,一個MN矩陣&#xff1a;表示它可以同時支持M路圖像輸入和N路圖像輸出。即任意的一個輸入和任意的一個輸出。 視頻矩陣 - 基本功能和要求 一個矩陣系統通常還應該包括以下基本功能&…

Spring 教程03

spring-3 1. Xml<!-- \src\applicationContext-xml.xml --> <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance…

讀書筆記之《The Art of Readable Code》Part 2

如何寫好流程控制語句(if-else/switch/while/for)使得代碼更可讀些&#xff1f;(chap 7)* 提高條件語句的可讀性(if語句, 或者bool型summary變量) if (length > 10) // Good if (10 < length) // Badwhile (bytes_received < bytes_expected) // Good while (b…

chisel快速入門(三)

前一篇見此&#xff1a; chisel快速入門&#xff08;二&#xff09;_滄海一升的博客-CSDN博客簡單介紹了chisel&#xff0c;使硬件開發者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121418806 十四、模塊的功能創建 制造用于模塊構造的功能接口也…

Redis作者攤上事了:多人要求修改Redis主從復制術語master/slave

作者 | ANTIREZ、小智近日&#xff0c;Redis 作者在 GitHub 上發起了一個“用其他詞匯代替 Redis 的主從復制術語”的 issue。有人認為 Redis 中的術語 master/slave &#xff08;主人 / 奴隸&#xff09;冒犯到了別人&#xff0c;要求 Redis 作者 ANTIREZ 修改這個術語&#x…

????C字符串數組賦值

C字符數組賦值 舉例如下&#xff1a; char a[10]; 1、定義的時候直接用字符串賦值 char a[10]"hello"; 注意&#xff1a;不能先定義再給它賦值&#xff0c;如 char a[10]; a[10]"hello"; 這樣是錯誤的&#xff01; 2、對數組中字符逐個賦值 char a[10]{h…

WP8.1使用HttpClient類

Uri uri new Uri("http://www.cnsos.net/weburl/index.htm", UriKind.Absolute); HttpClient myClient new HttpClient(); string result await myClient.GetStringAsync(uri); await new MessageDialog(result).ShowAsync(); 轉載于:https://www.cnblogs.com/wzw…

HttpClinet學習筆記

本文為學習httpClient學習過程中轉載的文章&#xff0c;若涉及版權請留言。 ----------------------------- 前言 超文本傳輸協議&#xff08;HTTP&#xff09;也許是當今互聯網上使用的最重要的協議了。Web服務&#xff0c;有網絡功能的設備和網絡計算的發展&#xff0c;都持續…