最近在看vue3官方文档watchEffect部分时,发现了一个tip:watchEffect 仅会在其同步执行期间,才追踪依赖。在使用异步回调时,只有在第一个 await 正常工作前访问到的属性才会被追踪。对于这句话不是很理解,自己先用写了个小例子试了一下,发现果然如此:修改count的值时,触发了副作用,但是修改msg时没有触发副作用执行。
javascript
import { ref, watchEffect } from 'vue'
const count = ref(0)
const msg = ref('hello')
watchEffect(async () => {
console.log('count:', count.value)
await new Promise(resolve => setTimeout(resolve, 100))
console.log('msg:', msg.value)})
// 测试:修改 count 会触发副作用(同步阶段依赖)
count.value = 1 // 触发 watchEffect,打印 count:1 和 msg:hello
// 测试:修改 msg 不会触发副作用(异步阶段未被追踪)
msg.value = 'world' // 无反应
带着疑问,开始寻找答案!
首先要知道watchEffect收集依赖的原理:watchEffect的参数是一个函数 fn,watchEffect会把函数执行一次,并创建响应式 Effect,收集依赖。简化为下面的代码:
javascript
let activeEffect = null
function watchEffect(fn) {
activeEffect = fn
fn()
activeEffect = null
}
也就是说,在fn执行期间,activeEffect的值是 fn,fn 执行完毕后,activeEffect的值是null。activeEffect是 Vue3 响应式设计的关键,vue3在对象 get 执行时,收集依赖,在 set 执行时执行依赖。
javascript
const effects = []
const count = {
_value: 1,
get value() {
if(activeEffect) {
effects.push(activeEffect)
}
return this._value
}
set value(val) {
this._value = val
effects.map((cb) => cb())
}
}
-
fn 函数在执行过程中,所有访问的响应式数据会触发 get 拦截器,get 函数里会对
activeEffect是否有值做判断,此时,activeEffect的值正是 fn,于是就把 fn 放入依赖队列里,watchEffect的依赖收集完成。 -
但是当遇到
await时,函数会 暂停执行,并将后续代码放入微任务队列。此时,当前 fn 的同步执行已结束,activeEffect会被重置。 -
当
await后的代码恢复执行时,activeEffect已不再指向当前watchEffect的 fn了,这也就解释了watchEffect仅会在其同步执行期间,才追踪依赖。
了解原理以后,这是由 JavaScript 异步机制和 Vue3 响应式的 activeEffect 设计决定的。
然而还有一种情况也会出现watchEffect不执行副作用的情况:
javascript
import { ref, watchEffect } from 'vue'
const count = ref(0)
let flag = false
watchEffect(() => {
if(flag) {
console.log('count的值改变了', count.value)
}
})
setTimeOut(() => {
flag = true
}, 1000)
setTimeOut(() => {
count.vaue++
}, 2000)
2秒后,控制台并没有打印信息。这是为什么呢?
watchEffect在执行时,flag 是 false,因此并没有执行 console.log('count的值改变了', count.value) 这句代码,没有访问响应式数据count,count的 get 拦截器也不会触发,所以并没有收集依赖。即使后面修改count的值,也不会触发副作用函数执行。
如果在开发过程中,发现watchEffect的副作用函数没有执行时,就要检查一下是不是上述两种情况了!
团队介绍
「智慧家技术平台-应用软件框架开发 」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。