vue.js源码 - 剖析observer,dep,watch三者关系 如何具体的实现数据双向绑定

Vue双向数据绑定的核心和基础api是Object.defineProperty,其内部真正参与数据双向绑定流程的主要有Obderver、Dep和Watcher,基于defineProperty和发布者订阅者模式,最终实现数据的双向绑定。那么Obderver、Dep和Watcher是如何具体配合工做的呢?下面就来理一理。vue

看此文章以前你须要对vue的双向数据绑定有必定的理解。若不了解可移步:vue.js源码解读系列 - 双向绑定具体如何初始化和工做git

看到这里就当你对双向数据绑定已经有必定的理解:github

提示:要看懂此篇文章你须要对vue的mvvm有必定的了解,并须要和专一的去理解,或者对照源码跟着走,否则就很难真的看懂。api

在这里把双向数据绑定分为两个流程:数组

一、收集依赖流程:闭包

observe -> 
walk -> 
defineReactive -> 
get -> 
dep.depend() -> 
watcher.addDep(new Dep()) -> 
watcher.newDeps.push(dep) -> 
dep.addSub(new Watcher()) -> 
dep.subs.push(watcher)

依赖收集会通过以上流程,最终watcher.newDeps数组中存放dep列表,dep.subs数组中存放watcher列表。mvvm

为何要进行依赖收集?性能

new Vue({
    data(){
        return {
             name:'zane',
             sex:'男'
        }
    }
})

有上面这个data,实际上页面只使用到了name,并无使用age,根据Object.defineProperty的转换,若是咱们设置了this.sex='女',那么Vue也会去执行一遍虚拟DOM的比较,这样就无形的浪费了一些性能,所以才须要作依赖收集,界面用到了就收集,没有用到就不收集。学习

咱们跟着流程走来理一遍源码:this

直接进入Object.defineProperty的get方法:

e5dGdRPBDDhzQQx67QEYKC3hNpKkRSZr.png?imageslim

考验你闭包能力的时候到了,这个dep对象就是一个闭包。记下来咱们看看dep.depend()方法的实现。

G58KCikan2X84WWGBWMYYfT3fx8apAwe.png?imageslim
先暂停一下,上面两处都用到了 Dep.target ,我也说了它就是一个Watcher实例化对象,你是否是很想搞懂它到底在哪里赋值的呢,不急请跟着我下面的代码看看。
8C87shS2yecZRDJhaCQGetnHA6dX2etb.png?imageslim
Mx3yJeS8WFsjC7tpWwGGGBSMzWpkkYJJ.png?imageslim
8C87shS2yecZRDJhaCQGetnHA6dX2etb.png?imageslim

搞懂了Dep.target等于一个Watche对象,如今继续回到以前的思路看watcher.addDep作了什么。
HHPhyK6Pm3FnHMhCjTBNCJFpnXxQdBb3.png?imageslim
eMiD8hFDJx2anPDJ8TXYcpTyT7DkaFci.png?imageslim
就这样依赖收集的流程就走完了,是否感受很绕。

总结:依赖收集最终在 watcher.newDeps 中push了闭包中传过来的dep对象,在dep.subs中push了初始化Vue是简历的Watcher对象,这个对象的,this.getter = expOrFn,传过来的expOrFn是后期数据更新页面渲染的核心步骤,须要沉下心来好好去理理。

二、视图更新流程:

set -> 
dep.notify() -> 
subs[i].update() -> 
watcher.run() || queueWatcher(this) -> 
watcher.get() || watcher.cb -> 
watcher.getter() -> 
vm._update() -> 
vm.__patch__()

视图更新会通过以上流程,最终调用Vue的虚拟Dom diff过程实时更新界面视图
33H7t3FZ3ZAXNbCykrRDntBXRX6CWPtr.png?imageslim
yGnXsTcXFbRWnJQA6TzZXQntD6cR6EAQ.png?imageslim
hCKYJrMfDYN8zMTCybCbB3XhZK6D8f2T.png?imageslim
HHDC4Xk6bjcMS4HTRZbnrk6seFJXTWyG.png?imageslim
6B2BKd8eNWTSZ7ckbEDfQjrZsBBw3JsC.png?imageslim
ywcMkrbMZJDxkw7w4er5dCJD28HHDNTR.png?imageslim

走到此处后面我就不去跟踪了,后面会调用vm.__patch__ 方法,进而执行虚拟DOM的diff过程实时的更新界面。

总结:
要很好的理解vue的数据双向绑定就要比较耐心,沉下心来慢慢理解,同时也须要对vue的源码有个大体的理解,否则你只会看的愈来愈烦躁愈来愈没有信心。

vue很好的利用了Object.defineProperty方法的 get和set方法,订阅者发布者的设计思路,巧妙的组织代码,值得咱们很深刻的去学习和理解,从而促使咱们更好的去使用它。谢谢尤大的无私奉献,让咱们提升了生产力,把更多的精力花到业务逻辑中去。

原文地址:https://github.com/wangweiang...

相关文章
相关标签/搜索