欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

通過圖帶你深入了解vue的響應(yīng)式原理

 更新時間:2019年06月21日 15:43:11   作者:laihuamin  
這篇文章主要介紹了通過圖帶你深入了解vue的響應(yīng)式原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,

前言

如果自己去實(shí)現(xiàn)數(shù)據(jù)驅(qū)動的模式,如何解決一下幾個問題:

  • 通過什么手段去知道我的數(shù)據(jù)變了?
  • 通過什么東西去同步更新視圖?

數(shù)據(jù)劫持——obvserver

我們需要知道數(shù)據(jù)的獲取和改變,數(shù)據(jù)劫持是最基礎(chǔ)的手段。在Obeserver中,我們可以看到代碼如下:

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// ...
},
set: function reactiveSetter (newVal) {
// ...
}
})

通過Object.defineProperty這個方法,我們可以在數(shù)據(jù)發(fā)生改變或者獲取的時候,插入一些自定義操作。同理,vue也是在這個方法中做依賴收集和派發(fā)更新的。

綁定和更新視圖——watcher

從初始化開始,我們渲染視圖的時候,便會生成一個watcher,他是監(jiān)視視圖中參數(shù)變化以及更新視圖的。代碼如下:

// 在mount的生命鉤子中
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)

當(dāng)然,我們可以保留疑問:

  • watcher是怎么去更新視圖的
  • 數(shù)據(jù)又是怎么和watcher聯(lián)動起來的

具體的綁定和更新的流程,我們到后續(xù)的依賴收集中講解。

我們先來講講響應(yīng)式系統(tǒng)中涉及到的設(shè)計(jì)模式。

發(fā)布訂閱模式

在發(fā)布訂閱模式中,發(fā)布者和訂閱者之間多了一個發(fā)布通道;一方面從發(fā)布者接收事件,另一方面向訂閱者發(fā)布事件;訂閱者需要從事件通道訂閱事件

以此避免發(fā)布者和訂閱者之間產(chǎn)生依賴關(guān)系

vue的響應(yīng)式流程

vue的響應(yīng)式系統(tǒng)借鑒了數(shù)據(jù)劫持和發(fā)布訂閱模式。

Vue用Dep作為一個中間者,解藕了Observer和Watcher之間的關(guān)系,使得兩者的職能更加明確。

那具體是如何來完成依賴收集和訂閱更新的呢?

依賴收集過程

依賴收集的流程

舉個例子

<div id="app">
{{ message }}
{{ message1 }}
<input type="text" v-model="message">
<div @click="changeMessage">改變message</div> 
</div>
var app = new Vue({
el: '#app',
data: {
message: '1',
message1: '2',
},
methods: {
changeMessage() {
this.message = '2'
}
},
watch: {
message: function(val) {
this.message1 = val
}
}
})

依賴收集流程圖:

如何看懂這個依賴收集流程?關(guān)鍵在watcher代碼中:

get () {
pushTarget(this)
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm)
} catch (e) {
// 省略
} finally {
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
}
return value
}

調(diào)用的這個this.getter有兩種,一種是key值的getter方法,還有一種是expOrFn,比如mounted中傳入的updateComponent。

如何防止重復(fù)收集

我們不妨想想什么才算是重復(fù)收集了?

筆者想到一種情況:就是dep數(shù)組中,出現(xiàn)了多個一樣的watcher。

比如renderWatch就容易被重復(fù)收集,因?yàn)槲覀冊趆tml模版中,會重復(fù)使用data中的某個變量。那他是如何去重的呢?

1、只有watch在執(zhí)行g(shù)et時,觸發(fā)的取數(shù)操作,才會被收集

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
// ...
}
return value
},
set: function reactiveSetter (newVal) {
// ...
dep.notify()
}
})

當(dāng)只有Dep.target這個存在的時候才進(jìn)行依賴收集。Dep.target這個值只有在watcher執(zhí)行g(shù)et方法的時候才會存在。

2、在dep.depend的時候會判斷watch的id

depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
addDep (dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}

我們會發(fā)現(xiàn),在depend過程中,會有一個newDepIds去記錄已經(jīng)存入的dep的id,當(dāng)一個watcher已經(jīng)被該dep存過時,便不再會進(jìn)行依賴收集操作。

派發(fā)更新過程

收集流程講完了,不妨在聽聽更新流程。

訂閱更新的流程

老例子

<div id="app">
{{ message }}
{{ message1 }}
<input type="text" v-model="message">
<div @click="changeMessage">改變message</div> 
</div>
var app = new Vue({
el: '#app',
data: {
message: '1',
message1: '2',
},
methods: {
changeMessage() {
this.message = '3'
}
},
watch: {
message: function(val) {
this.message1 = val
}
}
})

依賴收集的最終結(jié)果:

當(dāng)觸發(fā)click事件的時候,便會觸發(fā)訂閱更新流程。

訂閱更新流程圖:

當(dāng)renderWatch執(zhí)行更新的時候,回去調(diào)用beforeUpdate生命鉤子,然后執(zhí)行patch方法,進(jìn)行視圖的變更。

如何防止重復(fù)更新

如何去防止重復(fù)更新呢?renderWatch會被很多dep進(jìn)行收集,如果視圖多次渲染,會造成性能問題。

其實(shí)問題的關(guān)在在于——queueWatcher

在queueWatcher中有兩個操作:去重和異步更新。

function queueWatcher (watcher) {
const id = watcher.id
if (has[id] == null) {
has[id] = true
queue.push(watcher)
// ...
if (!waiting) {
waiting = true
// ...
nextTick(flushSchedulerQueue)
}
}
}

其實(shí)queueWatcher很簡單,將所有watch收集到一個數(shù)組當(dāng)中,然后去重。

這樣至少可以避免renderWatch頻繁更新。

比如上述例子中的,message和message1都有一個renderWatch,但是只會執(zhí)行一次。

異步更新也可以保證當(dāng)一個事件結(jié)束之后,才會觸發(fā)視圖層的更新,也能防止renderWatch重復(fù)更新

結(jié)尾

文章講述了響應(yīng)式流程的原因,代碼細(xì)節(jié)并未深入,

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Vue 單文件中的數(shù)據(jù)傳遞示例

    Vue 單文件中的數(shù)據(jù)傳遞示例

    本篇文章主要介紹了Vue 單文件中的數(shù)據(jù)傳遞示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • Vue數(shù)據(jù)綁定簡析小結(jié)

    Vue數(shù)據(jù)綁定簡析小結(jié)

    這篇文章主要介紹了Vue數(shù)據(jù)綁定簡析小結(jié),本文將從源碼的角度來對Vue響應(yīng)式數(shù)據(jù)中的觀察者模式進(jìn)行簡析。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • 解決vue項(xiàng)目中出現(xiàn)Invalid Host header的問題

    解決vue項(xiàng)目中出現(xiàn)Invalid Host header的問題

    這篇文章主要介紹了解決vue項(xiàng)目中出現(xiàn)"Invalid Host header"的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 詳解Vue.js v-for不支持IE9的解決方法

    詳解Vue.js v-for不支持IE9的解決方法

    這篇文章主要介紹了詳解Vue.js v-for不支持IE9的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • 關(guān)于前端報“應(yīng)為聲明或語句。ts(1128)“的原因及解決方案

    關(guān)于前端報“應(yīng)為聲明或語句。ts(1128)“的原因及解決方案

    最近在學(xué)習(xí)中遇到了個不常見的報錯,這里給大家總結(jié)下解決的辦法,這篇文章主要給大家介紹了關(guān)于前端報“應(yīng)為聲明或語句,ts(1128)“的原因及解決方案,需要的朋友可以參考下
    2024-08-08
  • vue踩坑記錄之?dāng)?shù)組定義和賦值問題

    vue踩坑記錄之?dāng)?shù)組定義和賦值問題

    這篇文章主要給大家介紹了關(guān)于vue踩坑記錄之?dāng)?shù)組定義和賦值問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • vue項(xiàng)目nginx二級域名配置方式

    vue項(xiàng)目nginx二級域名配置方式

    這篇文章主要介紹了vue項(xiàng)目nginx二級域名配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • ElementUI實(shí)現(xiàn)el-table列寬自適應(yīng)的代碼詳解

    ElementUI實(shí)現(xiàn)el-table列寬自適應(yīng)的代碼詳解

    這篇文章給大家介紹了ElementUI實(shí)現(xiàn)el-table列寬自適應(yīng)的詳細(xì)步驟,文中通過代碼示例給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-01-01
  • 在vue中實(shí)現(xiàn)嵌套頁面(iframe)

    在vue中實(shí)現(xiàn)嵌套頁面(iframe)

    這篇文章主要介紹了在vue中實(shí)現(xiàn)嵌套頁面(iframe),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Vue分頁插件的前后端配置與使用

    Vue分頁插件的前后端配置與使用

    這篇文章主要為大家詳細(xì)介紹了Vue分頁插件的前后端配置與使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10

最新評論