热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

VUEMVVMpart4优化Watcher

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。回顾首先我们思考一下截止当前,我们都做了什么通过defineReactive这个函数,实现了对于数据取值和设置的监

看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。

回顾

首先我们思考一下截止当前,我们都做了什么

  1. 通过 defineReactive 这个函数,实现了对于数据取值和设置的监听
  2. 通过 Dep 类,实现了依赖的管理
  3. 通过 Watcher 类,抽象出了对象下某个属性的依赖,以及属性变换的 callBack

发现问题

对比 VueMVVM(先把视图层的渲染抽象成一个函数),我们仅仅是实现了一些基础性的东西。还有很大的区别,比如

  1. 我们的 Watcher 仅仅是抽象了对象下的单一属性,而一般视图层的渲染是涉及多个属性的,而这些属性的变化是同一个渲染函数(也就是 Vue 中编译模板字符串最终生成的函数)。
  2. 通过第一点,我们可以得知,对象下的某几个属性是拥有同一个 Watcher 的,换句话说就是,多个 Dep 依赖与同一个 Watcher,那么 Watcher 中该如何保存这些 Dep ,因为按照我们的实现,都一个 Watcher 中仅仅保持一个 Dep

解决问题

问题1

先让我们想想,我们是如何把依赖注入到 Dep 中的

通过取值触发 defineProperty 中的 get,然后添加依赖

换句话说就是,我只要取过对应属性的值,那么就可以添加依赖。
看到之前 Watcher 的实现:

this.get = function () {
Dep.target = this
let value = this.getter.call(object)
Dep.target = null
return value
}

这段代码就实现了添加相应属性的依赖,归根到底是这段起了作用

let value = this.obj[this.getter]

这里触发了对应属性的 get ,那好针对第一个问题,我们只要在这里触发多个属性的 get 即可,至于要触发那些属性,我们交由调用者来控制,顺理成章的这里应该是一个函数。考虑之后便有了以下代码

let Watcher = function (object, getter, callback) {
this.obj = object
// 这里的 getter 应该是一个函数
this.getter = getter
this.cb = callback
this.dep = null
this.value = undefined
this.get = function () {
Dep.target = this
// 将取值方式改成函数调用
let value = this.getter.call(object)
Dep.target = null
return value
}
this.update = function () {
const value = this.getter.call(object)
const oldValue = this.value
this.value = value
this.cb.call(this.obj, value, oldValue)
}
this.addDep = function (dep) {
this.dep = dep
}
this.value = this.get()
}

问题二

问题二其实很简单,既然要保存多个 dep 我们把保存的值声明成一个数组即可

let Watcher = function (object, getter, callback) {
this.obj = object
this.getter = getter
this.cb = callback
// 声明成数组
this.deps = []
this.value = undefined
this.get = function () {
Dep.target = this
let value = this.getter.call(object)
Dep.target = null
return value
}
this.update = function () {
const value = this.getter.call(object)
const oldValue = this.value
this.value = value
this.cb.call(this.obj, value, oldValue)
}
this.addDep = function (dep) {
// 将 dep 推入数组中
this.deps.push(dep)
}
this.value = this.get()
}

为了方便取消这个 Watcher ,我们在添加一个函数,用于取消所有 DepWatcher 的依赖,所以最终 Watcher 的代码如下:

let Watcher = function (object, getter, callback) {
this.obj = object
this.getter = getter
this.cb = callback
this.deps = []
this.value = undefined
this.get = function () {
Dep.target = this
let value = this.getter.call(object)
Dep.target = null
return value
}
this.update = function () {
const value = this.getter.call(object)
const oldValue = this.value
this.value = value
this.cb.call(this.obj, value, oldValue)
}
this.addDep = function (dep) {
this.deps.push(dep)
}
// 新添加的取消依赖的方法
this.teardown = function () {
let i = this.deps.length
while (i--) {
this.deps[i].removeSub(this)
}
this.deps = []
}
this.value = this.get()
}

测试

我们仅仅优化了 Watcher 的实现,其他的代码并没有发生变化

let object = {}
defineReactive(object, 'num1', 2)
defineReactive(object, 'num2', 4)
let watcher = new Watcher(object, function () {
return this.num1 + this.num2
}, function (newValue, oldValue) {
console.log(`这是一个监听函数,${object.num1} + ${object.num2} = ${newValue}`)
})
object.num1 = 3
// 这是一个监听函数,3 + 4 = 7
object.num2 = 10
// 这是一个监听函数,3 + 10 = 13
let watcher2 = new Watcher(object, function () {
return this.num1 * this.num2
}, function (newValue, oldValue) {
console.log(`这是一个监听函数,${object.num1} * ${object.num2} = ${newValue}`)
})
object.num1 = 4
// 这是一个监听函数,4 + 10 = 14
// 这是一个监听函数,4 * 10 = 40
object.num2 = 11
// 这是一个监听函数,4 + 11 = 15
// 这是一个监听函数,4 * 11 = 44
// 测试取消
watcher2.teardown()
object.num1 = 5
// 这是一个监听函数,5 + 11 = 16
object.num2 = 12
// 这是一个监听函数,5 + 12 = 17

这就实现了对于多个属性设置同一个监听,当监听函数中的依赖属性发生变化时,自动执行了相应的函数。

关于 Vue 中的 MVVM 的实现 ,差不多也就这样了,当然这仅仅是基础的实现,而且视图层层渲染抽象成一个函数。

不同于 Vue 中的实现,这里少了很多各种标记和应用标记的过程。

这些会增加理解难度,之后有用到再说,实现完整的 MVVM 还需要对数组进行特殊的处理,因为数组是不能用 Object.defineProperty 来处理索引值的,这个也之后再说。

点击查看相关代码

系列文章地址

  1. VUE – MVVM – part1 – defineProperty
  2. VUE – MVVM – part2 – Dep
  3. VUE – MVVM – part3 – Watcher
  4. VUE – MVVM – part4 – 优化Watcher
  5. VUE – MVVM – part5 – Observe
  6. VUE – MVVM – part6 – Array
  7. VUE – MVVM – part7 – Event
  8. VUE – MVVM – part8 – 优化Event
  9. VUE – MVVM – part9 – Vue
  10. VUE – MVVM – part10 – Computed
  11. VUE – MVVM – part11 – Extend
  12. VUE – MVVM – part12 – props
  13. VUE – MVVM – part13 – inject & 总结

推荐阅读
  • Vue的组件化
    文章目录Vue的组件化一、认识组件化1.什么是组件化2.组件化思想二、注册组件1.组件的使用步骤三、组件其他补充1.全局组件和局部组件2.父组件和子组件3.组件的语法糖写法4.组件 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • C#设计模式之八装饰模式(Decorator Pattern)【结构型】
    一、引言今天我们要讲【结构型】设计模式的第三个模式,该模式是【装饰模式】,英文名称:DecoratorPattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理 ... [详细]
  • 本文涉及源码版本为2.6.9准备工作down一份Vue源码,从package.json入手,找我们需要的代码1、package.json中的scripts,build:nodesc ... [详细]
  • Vue.Js_Vue之vue.js声明式渲染
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Vue之vue.js声明式渲染相关的知识,希望对你有一定的参考价值。ht ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文介绍了在使用vue和webpack进行异步组件按需加载时可能出现的报错问题,并提供了解决方法。同时还解答了关于局部注册组件和v-if指令的相关问题。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了如何使用动态尺寸巧妙地将R中的数组子集化。作者通过解释数组的三个维度以及第三个维度的长度可变性,提出了一种周期性子集化数组的方法,并举例说明了如何创建第二个数组。这个方法对于制作模拟模型非常有用。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 详解 Python 的二元算术运算,为什么说减法只是语法糖?[Python常见问题]
    原题|UnravellingbinaryarithmeticoperationsinPython作者|BrettCannon译者|豌豆花下猫(“Python猫 ... [详细]
  • vue.js如何实现数据的双向绑定呢?与angular不同。vue利用的是es5的defineproperty特性。1.一个小例子 ... [详细]
author-avatar
魏承辉符合_821
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有