<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        深入理解Vue Computed計算屬性原理

        來源:懂視網 責編:小采 時間:2020-11-27 22:14:04
        文檔

        深入理解Vue Computed計算屬性原理

        深入理解Vue Computed計算屬性原理:Computed 計算屬性是 Vue 中常用的一個功能,但你理解它是怎么工作的嗎? 拿官網簡單的例子來看一下: <div id=example> <p>Original message: {{ message }}</p> <p>Computed reverse
        推薦度:
        導讀深入理解Vue Computed計算屬性原理:Computed 計算屬性是 Vue 中常用的一個功能,但你理解它是怎么工作的嗎? 拿官網簡單的例子來看一下: <div id=example> <p>Original message: {{ message }}</p> <p>Computed reverse

        Computed 計算屬性是 Vue 中常用的一個功能,但你理解它是怎么工作的嗎?

        拿官網簡單的例子來看一下:

        <div id="example">
         <p>Original message: "{{ message }}"</p>
         <p>Computed reversed message: "{{ reversedMessage }}"</p>
        </div>
        
        var vm = new Vue({
         el: '#example',
         data: {
         message: 'Hello'
         },
         computed: {
         // a computed getter
         reversedMessage: function () {
         // `this` points to the vm instance
         return this.message.split('').reverse().join('')
         }
         }
        })
        

        Situation

        Vue 里的 Computed 屬性非常頻繁的被使用到,但并不是很清楚它的實現原理。比如:計算屬性如何與屬性建立依賴關系?屬性發生變化又如何通知到計算屬性重新計算?

        關于如何建立依賴關系,我的第一個想到的就是語法解析,但這樣太浪費性能,因此排除,第二個想到的就是利用 JavaScript 單線程的原理和 Vue 的 Getter 設計,通過一個簡單的發布訂閱,就可以在一次計算屬性求值的過程中收集到相關依賴。

        因此接下來的任務就是從 Vue 源碼一步步分析 Computed 的實現原理。

        Task

        分析依賴收集實現原理,分析動態計算實現原理。

        Action

        data 屬性初始化 getter setter:

        // src/observer/index.js
        
        // 這里開始轉換 data 的 getter setter,原始值已存入到 __ob__ 屬性中
        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()
         }
        })
        
        

        computed 計算屬性初始化

        // src/core/instance/state.js
        
        // 初始化計算屬性
        function initComputed (vm: Component, computed: Object) {
         ...
         // 遍歷 computed 計算屬性
         for (const key in computed) {
         ...
         // 創建 Watcher 實例
         // create internal watcher for the computed property.
         watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions)
        
         // 創建屬性 vm.reversedMessage,并將提供的函數將用作屬性 vm.reversedMessage 的 getter,
         // 最終 computed 與 data 會一起混合到 vm 下,所以當 computed 與 data 存在重名屬性時會拋出警告
         defineComputed(vm, key, userDef)
         ...
         }
        }
        
        export function defineComputed (target: any, key: string, userDef: Object | Function) {
         ...
         // 創建 get set 方法
         sharedPropertyDefinition.get = createComputedGetter(key)
         sharedPropertyDefinition.set = noop
         ...
         // 創建屬性 vm.reversedMessage,并初始化 getter setter
         Object.defineProperty(target, key, sharedPropertyDefinition)
        }
        
        function createComputedGetter (key) {
         return function computedGetter () {
         const watcher = this._computedWatchers && this._computedWatchers[key]
         if (watcher) {
         if (watcher.dirty) {
         // watcher 暴露 evaluate 方法用于取值操作
         watcher.evaluate()
         }
         // 同第1步,判斷是否處于依賴收集狀態
         if (Dep.target) {
         watcher.depend()
         }
         return watcher.value
         }
         }
        }
        
        

        無論是屬性還是計算屬性,都會生成一個對應的 watcher 實例。

        // src/core/observer/watcher.js
        
        // 當通過 vm.reversedMessage 獲取計算屬性時,就會進到這個 getter 方法
        get () {
         // this 指的是 watcher 實例
         // 將當前 watcher 實例暫存到 Dep.target,這就表示開啟了依賴收集任務
         pushTarget(this)
         let value
         const vm = this.vm
         try {
         // 在執行 vm.reversedMessage 的函調函數時,會觸發屬性(步驟1)和計算屬性(步驟2)的 getter
         // 在這個執行過程中,就可以收集到 vm.reversedMessage 的依賴了
         value = this.getter.call(vm, vm)
         } catch (e) {
         if (this.user) {
         handleError(e, vm, `getter for watcher "${this.expression}"`)
         } else {
         throw e
         }
         } finally {
         if (this.deep) {
         traverse(value)
         }
         // 結束依賴收集任務
         popTarget()
         this.cleanupDeps()
         }
         return value
        }
        
        

        上面多出提到了 dep.depend, dep.notify, Dep.target,那么 Dep 究竟是什么呢?

        Dep 的代碼短小精悍,但卻承擔著非常重要的依賴收集環節。

        // src/core/observer/dep.js
        
        export default class Dep {
         static target: ?Watcher;
         id: number;
         subs: Array<Watcher>;
        
         constructor () {
         this.id = uid++
         this.subs = []
         }
        
         addSub (sub: Watcher) {
         this.subs.push(sub)
         }
        
         removeSub (sub: Watcher) {
         remove(this.subs, sub)
         }
        
         depend () {
         if (Dep.target) {
         Dep.target.addDep(this)
         }
         }
        
         notify () {
         const subs = this.subs.slice()
         for (let i = 0, l = subs.length; i < l; i++) {
         // 更新 watcher 的值,與 watcher.evaluate() 類似,
         // 但 update 是給依賴變化時使用的,包含對 watch 的處理
         subs[i].update()
         }
         }
        }
        
        // 當首次計算 computed 屬性的值時,Dep 將會在計算期間對依賴進行收集
        Dep.target = null
        const targetStack = []
        
        export function pushTarget (_target: Watcher) {
         // 在一次依賴收集期間,如果有其他依賴收集任務開始(比如:當前 computed 計算屬性嵌套其他 computed 計算屬性),
         // 那么將會把當前 target 暫存到 targetStack,先進行其他 target 的依賴收集,
         if (Dep.target) targetStack.push(Dep.target)
         Dep.target = _target
        }
        
        export function popTarget () {
         // 當嵌套的依賴收集任務完成后,將 target 恢復為上一層的 Watcher,并繼續做依賴收集
         Dep.target = targetStack.pop()
        }
        
        

        Result

        總結一下依賴收集、動態計算的流程:

        1. data 屬性初始化 getter setter

        2. computed 計算屬性初始化,提供的函數將用作屬性 vm.reversedMessage 的 getter

        3. 當首次獲取 reversedMessage 計算屬性的值時,Dep 開始依賴收集

        4. 在執行 message getter 方法時,如果 Dep 處于依賴收集狀態,則判定 message 為 reversedMessage 的依賴,并建立依賴關系

        5. 當 message 發生變化時,根據依賴關系,觸發 reverseMessage 的重新計算
        到此,整個 Computed 的工作流程就理清楚了。

        Vue 是一個設計非常優美的框架,使用 Getter Setter 設計使依賴關系實現的非常順其自然,使用計算與渲染分離的設計(優先使用 MutationObserver,降級使用 setTimeout)也非常貼合瀏覽器計算引擎與排版引擎分離的的設計原理。

        如果你想成為一名架構師,不能只停留在框架的 API 使用層面。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        深入理解Vue Computed計算屬性原理

        深入理解Vue Computed計算屬性原理:Computed 計算屬性是 Vue 中常用的一個功能,但你理解它是怎么工作的嗎? 拿官網簡單的例子來看一下: <div id=example> <p>Original message: {{ message }}</p> <p>Computed reverse
        推薦度:
        標簽: 原理 VUE 計算屬性
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲国产激情在线一区| 亚洲国产精品自在线一区二区| 亚洲成AV人片久久| 成全高清在线观看免费| 国产亚洲精品久久久久秋霞| 日韩在线观看视频免费| 免费在线观看中文字幕| 牛牛在线精品免费视频观看| 狠狠色婷婷狠狠狠亚洲综合| 国产三级在线免费观看| 亚洲午夜无码久久久久| 日本免费人成网ww555在线| 内射少妇36P亚洲区| 91久久精品国产免费直播| 亚洲香蕉在线观看| 好大好深好猛好爽视频免费| 亚洲6080yy久久无码产自国产| 免费一级毛片免费播放| 国产免费人成视频在线播放播| 亚洲av网址在线观看| 黄色永久免费网站| 亚洲精品无播放器在线播放 | 国产亚洲精品第一综合| 免费中文字幕在线观看| 中文字幕免费在线视频| 4444亚洲国产成人精品| 久久精品女人天堂AV免费观看 | 九九热久久免费视频| 香蕉蕉亚亚洲aav综合| 免费三级毛片电影片| 男男gvh肉在线观看免费| 久久久久亚洲AV无码专区桃色| 久草免费手机视频| 亚洲人成网站18禁止| 国产AV无码专区亚洲AV漫画| 91香蕉国产线在线观看免费| 亚洲国产精品成人午夜在线观看| 亚洲熟伦熟女新五十路熟妇| h视频在线免费看| 日本高清不卡中文字幕免费| 亚洲高清中文字幕|