vue computed 实现原理与 watch 对比

原理

<div id="app">
  {{num}}
  {{num1}}
</div>

var app = new Vue({
  el: '#app',
  data: {
    num: 1
  },
  computed: {
    num1 () {
      return this.num + 1;
    }
  }
});
console.log(app);

computed 本质是一个惰性求值的订阅者。data 属性的 Observer 挂在 _data 属性下,而 computed 属性挂在 _computedWatchers 下。而发布者 Dep 里存放了两个订阅者,而和computed相关的订阅者,其实只做了一件事情,标记 dirty 为 true,等待 get 时再真正计算。

computed 内部实现了一个惰性的 watcher,也就是 _computedWatchers,_computedWatchers 不会立刻求值,同时持有一个 dep 实例。

其内部通过 this.dirty 属性标记计算属性是否需要重新求值

变更流程如下:

  1. 当 computed 的依赖的状态发生改变时,就会通知这个惰性的 watcher。
  2. computed watcher 通过 this.dep.subs.length 判断有没有订阅者,
    1. 有的话,会重新计算,然后对比新旧值,如果变化了,会重新渲染。 (Vue 想确保不仅仅是计算属性依赖的值发生变化,而是当计算属性最终计算的值发生变化时才会触发渲染 watcher 重新渲染,本质上是一种优化。)
    2. 没有的话,仅仅把 this.dirty = true。 (当计算属性依赖于其他数据时,属性并不会立即重新计算,只有之后其他地方需要读取属性的时候,它才会真正计算,即具备 lazy(懒计算)特性。)

watch

这是 computed 的 watcher 观察者结构。特有的 lazy 为 true 代表 getter 时需要计算更新,注意 cb 只是一个空的函数,啥也不做,但是 expression 有值

Watcher {
    vm: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
    deep: false
    user: false
    lazy: true
    sync: false
    before: undefined
    cb: function noop(a, b, c) {}
    id: 1
    active: true
    dirty: false
    deps: (2) [Dep, Dep]
    newDeps: []
    depIds: Set(2) {3, 6}
    newDepIds: Set(0) {}
    expression: "len() {?        return this.message.length?      }"
    getter: ? len()
    value: 2
    __proto__: Object
}

这是 watch 的 观察者结构,注意 user 为 true,expression 里没有关键内容,但是 cb 里有,更新值的时候就是判定 user 为 true 时,调用 cb 获取新值。

Watcher {
    vm: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
    deep: false
    user: true
    lazy: false
    sync: false
    before: undefined
    cb: function message() {
        this.full = this.message.join(',');
    }
    id: 2
    active: true
    dirty: false
    deps: (2) [Dep, Dep]
    newDeps: []
    depIds: Set(2) {3, 6}
    newDepIds: Set(0) {}
    expression: "message"
    getter: ? (obj)
    value: (2) ["a", "c", __ob__: Observer],
    __proto__: Object
}

与 watch 有什么区别

computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。

watch 侦听器 : 更多的是「观察」的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。

与 watch 运用场景的对比

需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算。

原文地址:https://www.cnblogs.com/everlose/p/12542011.html

时间: 2024-08-30 17:12:14

vue computed 实现原理与 watch 对比的相关文章

深度解析 Vue 响应式原理

深度解析 Vue 响应式原理 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还是进阶,亦或是源码解读,你都能在本图谱中得到满意的答案,希望这个面试图谱能够帮助到大家更好的准备面试. Vue 初始化 在 Vue 的初始化中,会先对 props 和 data 进行初始化 Vue.prototype._init = function(options?: Object) { // ...

深入Vue响应式原理

深入Vue.js响应式原理 一.创建一个Vue应用 new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h => h(App), }).$mount('#app'); 二.实例化一个Vue应用到底发生了什么? this._init() callHook(vm, 'beforeCreate') observe(vm._data) vm._data = vm.$options.data() proxy(vm, _

[Vue源码]一起来学Vue双向绑定原理-数据劫持和发布订阅

有一段时间没有更新技术博文了,因为这段时间埋下头来看Vue源码了.本文我们一起通过学习双向绑定原理来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsun

自定义vue全局组件use使用(解释vue.use()的原理)

我们在前面学习到是用别人的组件:Vue.use(VueRouter).Vue.use(Mint)等等.其实使用的这些都是全剧组件,这里我们就来讲解一下怎么样定义一个全局组件,并解释vue.use()的原理而我们再用Axios做交互,则不能使用Vue.use(Axios),因为Axios没有install 自定义一个全局Loading组件,并使用:总结目录:|-components |-loading |-index.js 导出组件,并且install |-loading.vue 定义Loadin

Vue computed 计算属性

<template> <div id="app"> <div>{{reverseTitle}}</div> <div>{{reverseTitle2()}}</div> <button @click="add()">补充货物1</button> <div>总价为:{{price}}</div> </div> </template&

vue响应式原理解析

# Vue响应式原理解析 首先定义了四个核心的js文件 - 1. observer.js 观察者函数,用来设置data的get和set函数,并且把watcher存放在dep中 - 2. watcher.js 监听者函数,用来设置dep.target开启依赖收集的条件,和触发视图的更新函数 - 3. compile.js 编译者函数,用来编译模版和实例化 watcher 函数 - 4. index.js 入口文件 注意dep函数就是一个壳子,用来存放watcher和触发watcher更新的 首先从

[Vue源码]一起来学Vue模板编译原理(一)-Template生成AST

本文我们一起通过学习Vue模板编译原理(一)-Template生成AST来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsunlei/javascrip

[Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串

本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsunlei/javascri

自己实现 一个 Vue框架,包含了Vue的核心原理

Vue工作机制 vue工作机制 Vue响应式的原理 依赖收集与追踪 编译compile html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <div id="app"> <!-- 插值绑定 --> <p>{{name}}<