面试官-你真的懂computed原理?(源码解读)

article/2024/9/7 19:07:52

要理解 computed 的工作原理,只需要理解下面4个特性

- 特性1:computed默认不执行(因为 lazy 的原因,在新建watcher实例的时候,会将 watcher.value 赋值为 undefined,而不会立马进行计算。)

- 特性2:取值的时候,computed里面的方法会被执行

- 特性3:computed是惰性的,computed依赖的其它属性发生变化时,computed不会立即重新计算,要等到获取computed的值,也就是求值的时候才会重新计算(依靠watcher中的lazy属性判断,如果lazy是true,则不执行函数)

- 特性4:computed是缓存的,如果computed依赖的其它属性没有发生变化,即使重新调用,也不会重新计算(依靠watcher中的dirty属性判断,如果dirty是true,则重新计算,否则不计算,直接取watcher内的缓存value)

用法

Vue中computed典型的用法有如下两种:

// 方式1:
computed: {fullName() {return this.firstName + this.lastName}
}
// 方式2:
computed: {fullName: {get() {console.log('ooo')return this.firstName + this.lastName},set() {console.log("set full name")}}
}

computed源码实现

vue在初始化的时候,如果发现传入的属性是一个computed,则对其进行初始化处理

export function initState(vm: Component) {const opts = vm.$optionsif (opts.props) initProps(vm, opts.props)// Composition APIinitSetup(vm)if (opts.methods) initMethods(vm, opts.methods)if (opts.data) {initData(vm)} else {const ob = observe((vm._data = {}))ob && ob.vmCount++}if (opts.computed) initComputed(vm, opts.computed) // 初始化if (opts.watch && opts.watch !== nativeWatch) {initWatch(vm, opts.watch)}
}

可以看出初始化的优先级是 props->setup->methods->data->computed->watch

initComputed函数

function initComputed(vm: Component, computed: Object) {const watchers = (vm._computedWatchers = Object.create(null))for (const key in computed) {const userDef = computed[key]// 对 computed 对象遍历,如果定义的是函数则直接取函数,不是则取对象内的get方法const getter = isFunction(userDef) ? userDef : userDef.getif (__DEV__ && getter == null) {warn(`Getter is missing for computed property "${key}".`, vm)}// 定义一个computed-wactherwatchers[key] = new Watcher(vm,getter || noop,noop,{ lazy: true })// 将key定义在vm上defineComputed(vm, key, userDef)}
}

  • computed是一个对象,首先要对其进行遍历。基于其用法的两种不同形式(函数和对象),会对其进行判断。对 computed 对象遍历,如果定义的是函数则直接取函数,不是则取对象内的get方法。

  • 在这里需要将每个computed的属性生成的watcher维护一个watchers,并且放在vm实例上。这样做的用处是,在创建computed getter的时候,可以顺利的获取到它的dirty属性。而dirty=lazy=true。

  • 然后将计算后的属性,定义到vm上

defineComputed方法

function defineComputed(vm, key, userDef) {const shouldCache = !isServerRendering()if (isFunction(userDef)) {//判断是否为缓存,如果不是每一次取值都会走get,如果发现是脏的,就重新获取,如果不是脏的,就不走getsharedPropertyDefinition.get = shouldCache? createComputedGetter(key): createGetterInvoker(userDef)sharedPropertyDefinition.set = noop} else {sharedPropertyDefinition.get = userDef.get? shouldCache && userDef.cache !== false? createComputedGetter(key): createGetterInvoker(userDef.get): noopsharedPropertyDefinition.set = userDef.set || noop}Object.defineProperty(target, key, sharedPropertyDefinition)
}
function createGetterInvoker(fn) {return function computedGetter() {return fn.call(this, this)}
}

在这个方法中,维护了一个sharedPropertyDefinition对象,用来存储defineProperty的第三个参数。这个对象中的get方法是一个自定义的get方法。即createComputedGetter(key)

之所以要用自定义的,是因为computed取值的时候,是有缓存的,如果没有变化,则不计算

从这里可以看出,computed依赖值发生变化的时候,是调用createComputedGetter的方法的。

createComputedGetter

一旦computed依赖的值发生变化,就会立刻进入这个方法。

function createComputedGetter(key) {return function computedGetter() {const watcher = this._computedWatchers && this._computedWatchers[key]if (watcher) {// 重点这段if (watcher.dirty) {watcher.evaluate()}if (Dep.target) {if (__DEV__ && Dep.target.onTrack) {Dep.target.onTrack({effect: Dep.target,target: this,type: TrackOpTypes.GET,key})}watcher.depend()}return watcher.value}}
}

在这个方法中,根据每一个watcher实例的dirty属性来判断是否执行计算方法。并返回计算过后的值。因为初始化的时候 dirty = true ,初始化调用 watcher 的evaluate 方法,其实这里可以看出 computed 的缓存就是通过dirty属性来判断,缓存数据存储在watcher的value属性。

watcher.get(重点:依赖数据watcher和computed的watcher互相绑定)

  evaluate() {this.value = this.get()this.dirty = false}
get() {pushTarget(this)// Dep.target = target 通过Dep保存当前 computed-watcher(Dep.target = target)并调用我们传入的函数let valueconst vm = this.vmtry {value = this.getter.call(vm, vm)} catch (e: any) {if (this.user) {handleError(e, vm, `getter for watcher "${this.expression}"`)} else {throw e}} finally {// "touch" every property so they are all tracked as// dependencies for deep watchingif (this.deep) {traverse(value)}popTarget()this.cleanupDeps()}return value}
export function pushTarget(target?: DepTarget | null) {targetStack.push(target)Dep.target = target
}

Dep.target = target,通过Dep保存当前 computed-watcher(Dep.target = target),所以当前的全局Dep.target保存的是 computed-watcher。当调用 this.getter.call(vm, vm) 会触发依赖项内部的属性的get方法。例如我们使用的是 fullName() { return this.firstName + this.lastName },当计算属性调用fullName 函数,触发 this.firstName 和 this.lastName的 get 方法(Observer类内)。

  Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {const value = getter ? getter.call(obj) : valif (Dep.target) {dep.depend()}return isRef(value) && !shallow ? value.value : value}})depend(info?: DebuggerEventExtraInfo) {if (Dep.target) {// 调用 computed-watcher 内的 addDep 方法Dep.target.addDep(this)}}

因为get方法是瞬时同步的,会拦截访问提前执行,执行dep.depend(),而 Dep.target = computed-watcher,会执行 watcher 的 addDep 方法。并且将 this(依赖数据的watcher)带到computed-watcher。

  addDep(dep: Dep) {const id = dep.idif (!this.newDepIds.has(id)) {this.newDepIds.add(id)this.newDeps.push(dep)if (!this.depIds.has(id)) {dep.addSub(this)}}}

实参 dep 是依赖数据的watcher,这时将computed的watcher添加到 data的watcher内 ,这样就实现data依赖 收集到 依赖computed的watcher,从而 data 变化时,会同时通知 computed 和 computed的地方。

需要注意的是,在computed的依赖属性的Dep上,收集了两个watcher:

  • computed的watcher
  • 渲染watcher

这两个watcher都会被执行。


http://chatgpt.dhexx.cn/article/mUuUYZL4.shtml

相关文章

ChatGPT的兴起的时代,国内chatgpt产品大盘点

1、 百度文心一言 2023年3月发布 文心一言​yiyan.baidu.com/ 2、阿里通义千问 2023年4月发布 通义千问​tongyi.aliyun.com/ 3、讯飞火星 2023年5月发布 讯飞星火认知大模型​xinghuo.xfyun.cn/ 4、360:360智脑 2023年4月发布 360智脑 x 360搜索邀您体验​…

ChatGPT是什么?为何会引爆国内算力需求?

过去十年中,通过“深度学习大算力”从而获得训练模型是实现人工智能的主流技术途径。由于深度学习、数据和算力这三个要素都已具备,全世界掀起了“大炼模型”的热潮,也催生了大批人工智能企业。 大模型是人工智能的发展趋势和未来 大模型&…

国内那么多AI专业,为什么国内却没有ChatGPT?

作者:赵俊博 Jake(浙大博导 AI专家) 浙大青椒,谢邀。以下纯为个人观点,不喜勿喷。 首先,我必须肯定一下ChatGPT,这个模型展现出来如下几个点让我震惊:(1)推…

你如何看待,“国内ChatGPT还没成熟,但ChatGPT的付费模式已经成熟了?”

作者:小傅哥 博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!😄 说来奇怪🤔,我们从0到1的事往往较少,但从1到100的嫁衣神功却很多也很快。就像 ChatGPT 还没有…

国内这么多“ChatGPT”是真是假

国内这些产品是真的吗?与国外的ChatGPT有什么联系? 用ChatGPT官方图标当头像 免费试用几次后开始收费 据澎湃科技报道,随手点开微信搜索框,就可以发现一系列与ChatGPT“沾亲带故”的产品,并以ChatGPT的官方图标为头像。…

国内版 ChatGPT 要来了?传百度有此计划

整理 | 苏宓 出品 | CSDN(ID:CSDNnews) ChatGPT 横空出现,引发 AIGC 热潮。虽然 ChatGPT 目前尚未面向国内普通用户开放,但是其彰显的潜力也引得很多开发者、企业跃跃欲试,这其中便包括了搜索引擎巨头百度。…

文心一言:中国版“ChatGPT”介绍与测评

👨‍💻作者简介: 大数据专业硕士在读,CSDN人工智能领域博客专家,阿里云专家博主,专注大数据与人工智能知识分享。公众号:GoAI的学习小屋 ,免费分享书籍、简历、导图等资料&#xff0…

借助国内ChatGPT平替+MindShow,飞速制作PPT

系列文章目录 借助国内ChatGPT平替markmap/Xmind飞速生成思维导图 借助国内ChatGPT平替剪映/百度AIGC平台快速制作短视频 利用ChatGPT编写Excel公式,对比讯飞星火与ChatGPT对Excel公式的回答 文章目录 系列文章目录前言一、科大讯飞“星火”认知大模型介绍二、使…

阿猫智能机器人称:国内用户轻松训练类ChatGPT等大语言模型,使得人人都能拥有自己的ChatGPT!

4月12日,微软宣布开源了Deep Speed Chat,帮助用户轻松训练类ChatGPT等大语言模型,使得人人都能拥有自己的ChatGPT!(国内chatgpt平台阿猫智能机器人项目合作地址:https://3amao.comGptChat, AI, APIhttps://…

不要让ChatGPT成为你的智商税

难处 我相信有部分人苦于政策,但是又没有途径,没法享受到chatGpt带来的便利。 我也相信有不少无良的人,在百度浏览器的各个官网搞什么接入openaiAPI的网站,欺骗广大人民交那么几十块。 这种行为本身不合理,也不合法…

全网唯一,不忽悠的ChatGPT

Datawhale干货 作者:Ben,中山大学,Datawhale成员 最近ChatGPT火出圈了,它和前阵子的Stable Diffusion(AIGC)一样成为社交媒体上人们津津乐道的话题。“ChatGPT要取代谷歌搜索了?”“ChatGPT要让…

两分钟成为 ChatGPT 国内高手【不要再拿ChatGPT当百度用了】

不要再问ChatGPT那些问百度的问题了,有更进阶的用法 更高效的编写prompts,以便ChatGPT给出更精准的回答 但是需要注意的是:国内现在根本没有GPT-4使用,但凡是说有GPT-4的都是骗子。 GPT 可以写文章,可以写诗&#x…

ChatGPT国内镜像站初体验:聊天、Python代码生成等

ChatGPT国内镜像站初体验,聊天、Python代码生成。 (本文获得CSDN质量评分【92】) 【学习的细节是欢悦的历程】 Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单……

chatgpt 国内版写代码功效 让技术人员轻松作业

上篇文章已经教过大家如何使用,由于很多程序员小伙伴想要看写代码如何 那么今天就简单的展示一下国内版写程序怎么样 废话不多说 咱们看效果 1 2 3 4 5 这个代码使用 Python 和 Pygame 实现了一个简单的俄罗斯方块游戏。运行代码后,您应该可以看到一个…

国内各大厂ChatGPT技术布局及应用场景

2023年无疑会是AIGC掀起浪潮的一年,自从微软投资的OpenAI 研究室发布了神仙级别的自然语言生成式AI——chatGPT之后,人工智能领域也算是被彻底“杀疯了”。 ​有人说,它诞生的意义不亚于Stable Diffusion等AI绘画生成模型的出现,…

用chatgpt写insar地质灾害的论文,重复率只有1.8%,chatgpt4.0写论文不是梦

突发奇想,想用chatgpt写一篇论文,并看看查重率,结果很惊艳,说明是确实可行的,请看下图。 下面是完整的文字内容。 InSAR (Interferometric Synthetic Aperture Radar) 地质灾害监测技术是一种基于合成孔径雷达…

找到了一篇介绍ChatGPT核心技术的论文

来源:智能化学习与思考 分布式实验室 本文约6100字,建议阅读9分钟 本文给大家分析ChatGPT背后的核心论文的要点和主要创新的初衷。 缘起 输入几个简单的关键词,AI能帮你生成一篇短篇小说甚至是专业论文。作为上知天文下知地理对话语言模型&am…

论文笔记——chatgpt评估+

文章目录 1. chatgpt 效果评估:Evaluating ChatGPT’s Information Extraction Capabilities: An Assessment of Performance, Explainability, Calibration, and Faithfulness文章简介文章结论 2. 事件抽取: OneEE: A One-Stage Framework for Fast Overlapping an…

ChatGPT 话题相关和类 ChatGPT 工具 | 优质文章、相关论文、应用、学习资源整理

文章目录 一、前言二、主要内容三、总结 🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 人工智能与手机和互联网一样具有革命性。 2023 年已经过去一半,ChatGPT 在今年以来一直备受瞩目。目前 ChatGPT 的更新速度逐渐放缓&#…

InstructGPT论文详解(学习ChatGPT必看论文)

InstructGPT论文详解(Training language models to follow instructions with human feedback,学习ChatGPT必看论文) 返回论文和资料目录 1.导读 继ChatGPT大火后,越来越多人想了解ChatGPT相关技术。OpenAI官网虽然没有给出Chat…