久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      Vue的響應(yīng)式原理是什么?

      最近看了不少Vue原理的文章,在這些文章的幫助下,我也多次嘗試自己理解Vue的源碼。終于,我覺(jué)得是時(shí)候自己輸出一下內(nèi)容了,希望可以從不同于其他文章的角度帶大家熟悉Vue。

      Vue的響應(yīng)式原理是什么?

      Dep

      var Dep = function Dep() {   this.id = uid++   this.subs = [] }

      Dep 的含義,自然就是 dependency(也就是依賴,一個(gè)計(jì)算機(jī)領(lǐng)域的名詞)。

      就像編寫(xiě) node.js 程序,常會(huì)使用 npm 倉(cāng)庫(kù)的依賴。在 Vue 中,依賴具體指的是響應(yīng)式處理后的數(shù)據(jù)。后面會(huì)提到,響應(yīng)式處理的關(guān)鍵函數(shù)之一是在很多 Vue 原理文章都會(huì)提到的 defineReactive。

      Dep 與每個(gè)響應(yīng)式數(shù)據(jù)綁定后,該響應(yīng)式數(shù)據(jù)就會(huì)成為一個(gè)依賴(名詞),下面介紹 Watcher 時(shí)會(huì)提到,響應(yīng)式數(shù)據(jù)可能被 watch、computed、在模板中使用 3 種情況依賴(動(dòng)詞)。

      subs

      Dep 對(duì)象下有一個(gè) subs 屬性,是一個(gè)數(shù)組,很容易猜出,就是 subscriber(訂閱者)列表的意思咯。訂閱者可能是 watch 函數(shù)、computed 函數(shù)、視圖更新函數(shù)。

      Watcher

      Watcher 是 Dep 里提到的訂閱者(不要和后面的 Observer 觀察者搞混)。

      因?yàn)?Watcher 的功能在于及時(shí)響應(yīng) Dep 的更新,就像一些 App 的訂閱推送,你(Watcher)訂閱了某些資訊(Dep),資訊更新時(shí)會(huì)提醒你閱讀。

      deps

      與 Dep 擁有 subs 屬性類似,Watcher 對(duì)象也有 deps 屬性。這樣構(gòu)成了 Watcher 和 Dep 就是一個(gè)多對(duì)多的關(guān)系,互相記錄的原因是當(dāng)一方被清除的時(shí)候可以及時(shí)更新相關(guān)對(duì)象。

      Watcher 如何產(chǎn)生

      上面多次提到的 watch、computed、渲染模板產(chǎn)生 Watcher,在 Vue 源碼里都有簡(jiǎn)明易懂的體現(xiàn):

      • mountComponent 的 vm._watcher = new Watcher(vm, updateComponent, noop);
      • initComputed 的 watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions)
      • $watcher 的 var watcher = new Watcher(vm, expOrFn, cb, options);

      Observer

      Observer 是觀察者,他負(fù)責(zé)遞歸地觀察(或者說(shuō)是處理)響應(yīng)式對(duì)象(或數(shù)組)。在打印出的實(shí)例里,可以注意到響應(yīng)式的對(duì)象都會(huì)帶著一個(gè) __ob__,這是已經(jīng)被觀察的證明。觀察者沒(méi)有上面的 Dep 和 Watcher 重要,稍微了解下就可以了。

      walk

      Observer.prototype.walk 是 Observer 初始化時(shí)遞歸處理的核心方法,不過(guò)此方法用于處理對(duì)象,另外還有 Observer.prototype.observeArray 處理數(shù)組。

      核心流程

      按照上面幾個(gè)概念的關(guān)系,如何搭配,該如何實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式更新?

      首先定下我們的目標(biāo):自然是在數(shù)據(jù)更新時(shí),自動(dòng)刷新視圖,顯示最新的數(shù)據(jù)。

      這就是上面提到的 Dep 和 Watcher 的關(guān)系,數(shù)據(jù)是 Dep,而 Watcher 觸發(fā)的是頁(yè)面渲染函數(shù)(這是最重要的 watcher)。

      但是新問(wèn)題隨之而來(lái),Dep 怎么知道有什么 Watcher 依賴于他?

      Vue 采用了一個(gè)很有意思的方法:

      • 在運(yùn)行 Watcher 的回調(diào)函數(shù)前,先記下當(dāng)前 Watcher 是什么(通過(guò) Dep.target)

      • 運(yùn)行回調(diào)函數(shù)中用到響應(yīng)式數(shù)據(jù),那么必然會(huì)調(diào)用響應(yīng)式數(shù)據(jù)的 getter 函數(shù)

      • 在響應(yīng)式數(shù)據(jù)的 getter 函數(shù)中就能記下當(dāng)前的 Watcher,建立 Dep 和 Watcher 的關(guān)系

      • 之后,在響應(yīng)式數(shù)據(jù)更新時(shí),必然會(huì)調(diào)用響應(yīng)式數(shù)據(jù)的 setter 函數(shù)

      • 基于之前建立的關(guān)系,在 setter 函數(shù)中就能觸發(fā)對(duì)應(yīng) Watcher 的回調(diào)函數(shù)了

      代碼

      上述邏輯就在 defineReactive 函數(shù)中。這個(gè)函數(shù)入口不少,這里先講比較重要的 observe 函數(shù)。

      在 observe 函數(shù)中會(huì) new Observer 對(duì)象,其中使用 Observer.prototype.walk 對(duì)對(duì)象中的值進(jìn)行逐個(gè)響應(yīng)式處理,使用的就是 defineReactive 函數(shù)。

      因?yàn)?defineReactive 函數(shù)太重要了,而且也不長(zhǎng),所以直接貼到這邊講比較方便。

      function defineReactive(obj, key, val, customSetter, shallow) {   var dep = new Dep()   depsArray.push({ dep, obj, key })   var property = Object.getOwnPropertyDescriptor(obj, key)   if (property && property.configurable === false) {     return   }    // cater for pre-defined getter/setters   var getter = property && property.get   var setter = property && property.set    var childOb = !shallow && observe(val)   Object.defineProperty(obj, key, {     enumerable: true,     configurable: true,     get: function reactiveGetter() {       var value = getter ? getter.call(obj) : val       if (Dep.target) {         dep.depend()         if (childOb) {           childOb.dep.depend()           if (Array.isArray(value)) {             dependArray(value)           }         }       }       return value     },     set: function reactiveSetter(newVal) {       var value = getter ? getter.call(obj) : val       // 后半部分詭異的條件是用于判斷新舊值都是 NaN 的情況       if (newVal === value || (newVal !== newVal && value !== value)) {         return       }       // customSetter 用于提醒你設(shè)置的值可能存在問(wèn)題       if ('development' !== 'production' && customSetter) {         customSetter()       }       if (setter) {         setter.call(obj, newVal)       } else {         val = newVal       }       childOb = !shallow && observe(newVal)       dep.notify()     },   }) }

      首先每個(gè)響應(yīng)式的值都是一個(gè)“依賴",所以第一步我們先借閉包的能力給每個(gè)值造一個(gè) Dep。(到 Vue 3 就不需要閉包啦)

      接著看核心的三個(gè)參數(shù):

      • obj 當(dāng)前需要響應(yīng)式處理的值所在的對(duì)象

      • key 值的 key

      • val 當(dāng)前的值

      這個(gè)值還可能之前就定義了自己的 getter、setter,所以在做 Vue 的響應(yīng)式處理時(shí)先處理原本的 getter、setter。

      上面在核心流程中提到在 getter 函數(shù)會(huì)建立 Dep 和 Watcher 的關(guān)系,具體來(lái)說(shuō)依靠的是 dep.depend()。

      下面貼一下 Dep 和 Watcher 互相調(diào)用的幾個(gè)方法:

      Dep.prototype.depend = function depend() {   if (Dep.target) {     Dep.target.addDep(this)   } } Watcher.prototype.addDep = function addDep(dep) {   var id = dep.id   if (!this.newDepIds.has(id)) {     this.newDepIds.add(id)     this.newDeps.push(dep)     if (!this.depIds.has(id)) {       dep.addSub(this)     }   } } Dep.prototype.addSub = function addSub(sub) {   this.subs.push(sub) }

      通過(guò)這幾個(gè)函數(shù),可以領(lǐng)略到了 Dep 和 Watcher 錯(cuò)綜復(fù)雜的關(guān)系……不過(guò)看起來(lái)迂回,簡(jiǎn)單來(lái)說(shuō),其實(shí)做的就是上面說(shuō)的互相添加到多對(duì)多列表。

      你可以在 Dep 的 subs 找到所有訂閱同一個(gè) Dep 的 Watcher,也可以在 Watcher 的 deps 找到所有該 Watcher 訂閱的所有 Dep。

      但是里面還有一個(gè)隱藏問(wèn)題,就是 Dep.target 怎么來(lái)呢?先放一放,后會(huì)作出解答。先接著看看 setter 函數(shù),其中的關(guān)鍵是 dep.notify()。

      Dep.prototype.notify = function notify() {   // stabilize the subscriber list first   var subs = this.subs.slice()   for (var i = 0, l = subs.length; i < l; i++) {     subs[i].update()   } }

      不難理解,就是 Dep 提醒他的訂閱者列表(subs)里的所有人更新,所謂訂閱者都是 Watcher,subs[i].update() 調(diào)用的也就是 Watcher.prototype.update。

      那么來(lái)看一下 Watcher 的 update 做了什么——

      Watcher.prototype.update = function update() {   if (this.lazy) {     this.dirty = true   } else if (this.sync) {     this.run()   } else {     queueWatcher(this)   } }

      在這里我覺(jué)得有兩個(gè)點(diǎn)比較值得展開(kāi),所以挖點(diǎn)坑

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)