0

0

vue响应式的原理是什么?vue响应式原理的分析

不言

不言

发布时间:2018-09-10 15:33:51

|

2748人浏览过

|

来源于php中文网

原创

本篇文章给大家带来的内容是关于vue响应式的原理是什么?vue响应式原理的分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

initState

new Vue() => _init() => initState:

function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

判断该vue实例是否存在props、methods、data、computed、watch进行调用相应的初始化函数

initProps与initData

主要工作是调用defineProperty给属性分别挂载get(触发该钩子时,会将当前属性的dep实例推入当前的Dep.target也就是当前watcher的deps中即它订阅的依赖,Dep.target下文会讲到。且该dep实例也会将当前watcher即观察者推入其subs数组中)、set方法(通知该依赖subs中所有的观察者watcher去调用他们的update方法)。

initComputed

它的作用是将computed对象中所有的属性遍历,并给该属性new一个computed watcher(计算属性中定义了个dep依赖,给需要使用该计算属性的watcher订阅)。也会通过调用defineProperty给computed挂载get(get方法)、set方法(set方法会判断是否传入,如果没传入会设置成noop空函数)
computed属性的get方法是下面函数的返回值函数

立即学习前端免费学习笔记(深入)”;

function createComputedGetter (key) {
  return function computedGetter () {
    const watcher = this._computedWatchers && this._computedWatchers[key]
    if (watcher) {
      watcher.depend()
      return watcher.evaluate()
    }
  }
}

注意其中的watcher.depend(),该方法让用到该属性的watcher观察者订阅该watcher中的依赖,且该计算属性watcher会将订阅它的watcher推入他的subs中(当计算属性值改变的时候,通知订阅他的watcher观察者)
watcher.evaluate(),该方法是通过调用watcher的get方法(其中需要注意的是watcher的get方法会调用pushTarget将之前的Dep.target实例入栈,并设置Dep.target为该computed watcher,被该计算属性依赖的响应式属性会将该computed watcher推入其subs中,所以当被依赖的响应式属性改变时,会通知订阅他的computed watcher,computed watcher 再通知订阅该计算属性的watcher调用update方法),get方法中调用计算属性key绑定的handler函数计算出值。

initWatch

该watcher 为user watcher(开发人员自己在组件中自定义的)。
initWatch的作用是遍历watch中的属性,并对每个watch监听的属性调用定义的$watch

Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): Function {
    const vm: Component = this
    if (isPlainObject(cb)) {
      return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {}
    options.user = true // 代表该watcher是用户自定义watcher
    const watcher = new Watcher(vm, expOrFn, cb, options)
    if (options.immediate) {
      cb.call(vm, watcher.value)
    }
    return function unwatchFn () {
      watcher.teardown()
    }
  }

代码中调用new Watcher的时候,也会同render watcher一样,执行下watcher的get方法,调用pushTarget将当前user watcher赋值给Dep.target,get()中value = this.getter.call(vm, vm)这个语句会触发该自定义watcher监听的响应式属性的get方法,并将当前的user watcher推入该属性依赖的subs中,所以当user watcher监听的属性set触发后,通知订阅该依赖的watcher去触发update,也就是触发该watch绑定的key对应的handler。然后就是调用popTarget出栈并赋值给Dep.target。

$mount

initState初始化工作大致到这里过,接下去会执行$mount开始渲染工作
$mount主要工作:new了一个渲染Watcher,并将updateCompent作为callback传递进去并执行

updateComponent = () => {
      vm._update(vm._render(), hydrating)
    }
new Watcher(vm, updateComponent, noop, {
    before () {
      if (vm._isMounted) {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)

三种watcher中new Watcher的时候,只有computed watcher不会一开始就执行它的get()方法。$mount里面new的这个render watcher会调用get()方法,调用pushTarget将当前render watcher赋值给Dep.target。接下去重头戏来了,调用updateComponent,该方法会执行vm._update(vm._render(), hydrating),其中render函数会触发html中使用到的响应式属性的get钩子。get钩子会让该响应式属性的依赖实例dep将当前的render watcher推入其subs数组中,所以当依赖的响应式属性改变之后,会遍历subs通知订阅它的watcher去调用update()。

例子

可能大家对watcher和dep调来调去一头雾水,我讲个实例

{{a}}
{{b}}
new Vue({ el: "#app", data() { return { a:1, } }, computed:{ b() { return a+1 } }, })

我直接从渲染开始讲,只讲跟dep跟watcher有关的
$mount:new一个渲染watcher(watcher的get方法中会将渲染watcher赋值给Dep.target)的时候会触发 vm._update(vm._render(), hydrating),render的时候会获取html中用到的响应式属性,上面例子中先用到了a,这时会触发a的get钩子,其中dep.depend()会将当前的渲染watcher推入到a属性的dep的subs数组中。

Magician
Magician

Figma插件,AI生成图标、图片和UX文案

下载

接下去继续执行,访问到b(b是计算属性的值),会触发计算属性的get方法。计算属性的get方法是调用createComputedGetter函数后的返回函数computedGetter,computedGetter函数中会执行watcher.depend()。Watcher的depend方法是专门留给computed watcher使用的。

刚才上面说过了除了computed watcher,其他两种watcher在new 完之后都会执行他们的get方法,那么computed watcher在new完之后干嘛呢,它会new一个dep。

回到刚才说的专门为computed watcher开设的方法watcher.depend(),他的作用是执行this.dep.depend()(computed watcher定义的dep就是在这里使用到的)。this.dep.depend()会让当前的渲染watcher订阅该计算属性依赖,该计算属性也会将渲染watcher推入到它自己的subs([render watcher])中,当计算属性的值修改之后会通知subs中的watcher调用update(),所以计算属性值变了页面能刷新。

回到前面说的触发b计算属性的get钩子那里,get钩子最后会执行watcher.evaluate(),watcher.evaluate()会执行computed watcher的get()方法。

这时候重点来了,会将Dep.target(render watcher)推入targetStack栈中(存入之后以便待会儿取出继续用),然后将这个计算属性的computed watcher赋值给Dep.target。get方法中value = this.getter.call(vm, vm),会执行computed属性绑定的handler。

如上面例子中return a + 1。使用了a那么就一定会触发a的get钩子,get钩子又会调用dep.depend(),dep.depend()会让computed watcher将dep存入它的deps数组中,a的dep会将当前的Dep.target(computed watcher)存入其subs数组中,当前例子中a的subs中就会是[render watcher,computed watcher],所以a值变化会遍历a的subs中的watcher调用update()方法,html中用到的a会刷新,计算属性watcher调用update()方法会通知他自己的subs([render watcher])中render watcher去调用update方法,html中用到的计算属性b才会刷新dom(这里提个醒,我只是粗略的讲,计算属性依赖的属性变化后他不一定会触发更新,他会比较计算完之后的值是否变化)。

computed watcher的get()方法最后会调用popTarget(),将之前存入render watcher出栈并赋值给Dep.target,这时候我例子中targetStack就变成空数组了。

render watcher的get方法执行到最后也会出栈,这时候会将Dep.target赋值会空。

相关推荐:

Vue数据响应式原理分析

在Vue中有关响应式原理(详细教程)

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

397

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

DOM是什么意思
DOM是什么意思

dom的英文全称是documentobjectmodel,表示文件对象模型,是w3c组织推荐的处理可扩展置标语言的标准编程接口;dom是html文档的内存中对象表示,它提供了使用javascript与网页交互的方式。想了解更多的相关内容,可以阅读本专题下面的文章。

3339

2024.08.14

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

16

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

12

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

563

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

200

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

336

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue 教程
Vue 教程

共42课时 | 7.4万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

Vue.js 微实战--十天技能课堂
Vue.js 微实战--十天技能课堂

共18课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号