博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么Proxy可以优化vue的数据监听机制
阅读量:7188 次
发布时间:2019-06-29

本文共 3088 字,大约阅读时间需要 10 分钟。

我们首先来看vue2.x中的实现,为简单起见,我们这里不考虑多级嵌套,也不考虑数组

vue2.x中的实现

其本质是new Watcher(data, key, callback)的方式,而在调用之前是先将data中的所有属性转化成可监听的对象, 其主要就是利用Object.defineProperty,。

class Watcher{    constructor(data, key, cb){    }}//转换成可监听对象function observe(data){    new Observer(data)}//修改数据的getter和setterfunction defineReactive(obj, key){    let value = obj[key];    Object.defineProperty(obj, key, {        enumerable: true,        configurable: true,        get(){            return value;        },        set(newVal){            value = newVal        }    })}复制代码

Observer的实现很简单

class Observer {    constructor(data){        this.walk(data);    }    walk(data){        for(var key in data) {            // 这里不考虑嵌套的问题,否则的话需要递归调用walk            defineReactive(data, key)        }    }}复制代码

现在怎么将watcher和getter/setter联系起来,vue的方法是添加一个依赖类:Dep

class Watcher{    constructor(data, key, cb){        this.cb = cb;        Dep.target = this; //每次新建watcher的时候讲给target赋值,对target的管理这里简化了vue的实现        data[key];//调用getter,执行addSub, 将target传入对应的dep; vue的实现本质就是如此    }}class Dep {    constructor(){        this.subs = [];    }    addSub(sub){        this.subs.push(sub);    }    notify(){        this.subs.forEach(sub => sub.cb())    }}function defineReactive(obj, key){    let value = obj[key];    let dep = new Dep(); //每一个属性都有一个对应的dep,作为闭包保存    Object.defineProperty(obj, key, {        enumerable: true,        configurable: true,        get(){            dep.addSub(Dep.target)            Dep.target = null;            return value;        },        set(newVal){            value = newVal            dep.notify();        }    })}复制代码

以上就是vue的思路,vue3之所以要从新实现,主要有这几个原因:

  1. Object.defineProperty的性能开销。
  2. defineReactive一开始就要对要监听的对象所有属性都执行一遍,因为传统方法要将一个对象转换成可监听对象,只能如此。
  3. 添加删除属性的问题。
  4. 还有一点就是这个模块被耦合到了vue里面,新版本可以单独作为一个库来使用。

然后我们来看看同样的功能采用Proxy会怎样实现。

Proxy的实现

将一个对象转换成Proxy的方式很简单,只需要作为参数传给proxy即可;

class Watcher {    constructor(proxy, key, cb) {        this.cb = cb;        Dep.target = this;        this.value = proxy[key];    }}class Dep {    constructor(){        this.subs = []    }    addSub(sub){        this.subs.push(sub);    }    notify(newVal){        this.subs.forEach(sub => {            sub.cb(newVal, sub.value);            sub.value = newVal;        })    }}const observe = (obj) => {    const deps = {};    return new Proxy(obj, {        get: function (target, key, receiver) {            const dep = (deps[key] = deps[key] || new Dep);            Dep.target && dep.addSub(Dep.target)            Dep.target = null;            return Reflect.get(target, key, receiver);        },        set: function (target, key, value, receiver) {            const dep = (deps[key] = deps[key] || new Dep);            Promise.resolve().then(() => {                dep.notify(value);            })            return Reflect.set(target, key, value, receiver);        }    });}var state = observe({
x:0})new Watcher(state, 'x', function(n, o){ console.log(n, o)});new Watcher(state, 'y', function(n, o){ console.log(n, o)});state.x = 3;state.y = 3;复制代码

也许一开始我们只关心xy,那么就不会对其他的属性做相应的处理,除非添加watcher,其他时间target都是null

如果有什么错误请指正,谢谢。

转载地址:http://knfkm.baihongyu.com/

你可能感兴趣的文章
.NET的XMPP开发包 MatriX
查看>>
JQuery easyui Datagrid 分页事件
查看>>
MPLS 转发原理
查看>>
android 手机型号,版本号,
查看>>
家庭宽带之IPv6网络测试
查看>>
让宏哥告诉你什么叫做 OO -- 放在博客比较有价值
查看>>
filter的时间过滤有关问题
查看>>
access手工注入笔记
查看>>
zookeeper原理(转)
查看>>
垂直居中的几种方法
查看>>
我的友情链接
查看>>
PTN960
查看>>
$_FILES[‘file’][‘error’] 错误代码和相关的错误常量
查看>>
将项目加入maven管理时报错
查看>>
Qt线程
查看>>
数据库小知识
查看>>
ASP.NET WEB API必知必会:特性路由
查看>>
'Worker' object has no attribute '_config'
查看>>
微信支付开发H5调用支付接口失败
查看>>
IIS安装及IIS无权访问解决方法(Failed to access IIS metabase解决)
查看>>