持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
4.7 调度执行
在前面几章,我们主要目标在完成一个基本可用的响应式,和修复响应式的bug.这一章会继续深入去探讨响应式的一些功能,可以叫完善的我们的响应式。
- 什么是调度 我们想象这样一个需要,我们需要一次打印出
1
2
结束
那么我们的代码,大概会是这样
const data = reactive({num:1})
effect(()=>{
consoloe.log(data.num)
})
data.num++
consoloe.log('结束')
如果我们需要的顺序变了,那么我们就需要修改代码才能调整顺序,这种其实叫做耦合,为什么不把执行的顺序作为外部输入呢?
这样,我们每次修改需求,其实就是修改外部的一个参数,而对于功能本身是不动的,这就是解耦,说高级一点就是依赖注入。
所以,在Vue.js中,设计了一个调度器,就是这样解决问题的。
我们在调用effect函数的时候,给他加上第二个参数,这个参数事一个对象,里面有一个scheduler,由于调度器其实本质上是控制流程的,因此它毫无疑问的是一个函数
effect(
()=>{consoloe.log(data.num)},
{scheduler(fn){}}
)
因此我们需要修改effect
const effect((fn,options={})=>{
const runEffect=()=>{
cleanup(runEffect) // 清除重复依赖
activeEffect = runEffect
effectStack.unshift(runEffect) //将副作用函数压入栈中
fn()
effectStack.pop() // 执行完成后,出栈
activeEffect = effectStack.at(-1) //将activeEffect对准栈底
}
runEffect.deps=[]
runEffect.options = options //新增,将options挂到对应的副作用函数上
runEffect()
})
那么,这个函数在哪里使用呢?自然是trigger时,当触发副作用函数的时候,我们可以去判断用户是否传入了调度器,如果传入我们就执行调度器,如果没有,那么就按顺序遍历即可。
我这里就不贴上之前写的trigger函数了,等把这一篇写完,我再整理代码,并写上详细注释
// 旧代码,仅是遍历执行
// effectToRun.forEach(fn=>fn())
effectToRun.forEach(fn=>{
//判断是否存在调度器,由于options已存在默认值,所以这里可以这样写
if(fn.options.scheduler){
fn.options.scheduler(fn)
} else {
fn()
}
})
是不是感觉很简单,确实实现起来很简单,但是我们更应该学习这个思想。
依赖注入又叫控制反转,其实从这个名字你就能大概猜到它的意思,其实就是把控制权或者依赖从外部传进来,大部分时候就是函数的传参,这样可以实现更好的解耦,比如axios的拦截器,也是这种思想。