Vue.js设计与实现读书笔记二 第四章 响应系统的作用与实现

第四章 响应系统的作用与实现

4.1 响应式数据与副作用函数

(1)什么是响应式数据?
响应式数据是当对象数据(设置)改变的时候,会执行读取数据的操作,读取数据操作的函数就是副作用函数

4.3 设计一个完善的响应式系统

// 存储副作用函数的桶
const bucket = new WeakMap()

// 原始数据
const data = { text: 'hello world' }
// 对原始数据的代理
const obj = new Proxy(data, {
  // 拦截读取操作
  get(target, key) {
    // 将副作用函数 activeEffect 添加到存储副作用函数的桶中
    track(target, key)
    // 返回属性值
    return target[key]
  },
  // 拦截设置操作
  set(target, key, newVal) {
    // 设置属性值
    target[key] = newVal
    // 把副作用函数从桶里取出并执行
    trigger(target, key)
  }
})

function track(target, key) {
  let depsMap = bucket.get(target)
  if (!depsMap) {
    bucket.set(target, (depsMap = new Map()))
  }
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, (deps = new Set()))
  }
  deps.add(activeEffect)
}

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  effects && effects.forEach(fn => fn())
}

// 用一个全局变量存储当前激活的 effect 函数
let activeEffect
function effect(fn) {
  // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
  activeEffect = fn
  // 执行副作用函数
  fn()
}

effect(() => {
  console.log('effect run')
  document.body.innerText = obj.text
})

setTimeout(() => {
  trigger(data, 'text')
}, 1000)

变量解释:
1.effect:他的参数fn是副作用函数,他是用来执行副作用函数,将副作用函数赋值给activeEffect这全局变量,这样做的好出是,让匿名的副作用函数,也能被bucket收集
2.fn:副作用函数,effect的参数,代理数据与DOM建立关系的函数
3.bucket :表示收集副作用函数,其结构是 {target -> key -> dep} 即,bucket由多个代理对象,每个代理对象由多个key,每个key有多个副作用函数
4.track 是当有代理对象的属性被读取,就将对应属性的副作用函数存储在bucket中
5.trigger 当代理对象的属性被修改,就将存储在bucket中的对应属性的副作用函数全部执行

代码执行流程是:effect(fn)执行,fn赋值给activeEffect,obj.text被读取,track被触发,
fn被存到了,bucket中,setTime执行,trigger执行,将刚刚存储的fn 被全部执行

注意:在代理中,getter是 track执行后才返回值,setter 是先设置值再执行trigger,后面分析打印顺序

4.4 分支切换与cleanup

<body></body>
<script>


// 存储副作用函数的桶
const bucket = new WeakMap()

// 原始数据
const data = { ok: true, text: 'hello world' }
// 对原始数据的代理
const obj = new Proxy(data, {
  // 拦截读取操作
  get(target, key) {
    // 将副作用函数 activeEffect 添加到存储副作用函数的桶中
    track(target, key)
    // 返回属性值
    return target[key]
  },
  // 拦截设置操作
  set(target, key, newVal) {
    // 设置属性值
    target[key] = newVal
    // 把副作用函数从桶里取出并执行
    trigger(target, key)
  }
})

function track(target, key) {
  let depsMap = bucket.get(target)
  if (!depsMap) {
    bucket.set(target, (depsMap = new Map()))
  }
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, (deps = new Set()))
  }
  deps.add(activeEffect)
  activeEffect.deps.push(deps)
  console.log("activeEffect",activeEffect.deps)
}

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)

  const effectsToRun = new Set()
  effects && effects.forEach(effectFn => effectsToRun.add(effectFn))
  effectsToRun.forEach(effectFn => effectFn())
  // effects && effects.forEach(effectFn => effectFn())
}

// 用一个全局变量存储当前激活的 effect 函数
let activeEffect
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()
  }
  // activeEffect.deps 用来存储所有与该副作用函数相关的依赖集合
  effectFn.deps = []
  // 执行副作用函数
  effectFn()
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       ]
    deps.delete(effectFn)
  }
  effectFn.deps.length = 0
}

effect(() => {
  console.log('effect run')
  document.body.innerText = obj.ok ? obj.text : 'not'
})

setTimeout(() => {
  obj.ok = false
  setTimeout(() => {
    obj.text = 'hello vue3'
  }, 1000)
}, 1000)

</script>

这个要解决的问题是obj.ok 开始是true的时候,执行副作用函数后,obj.ok改为false,修改obj.text不让他执行他的副作用函数。这是优化性能

这里主要做的改进是,当同一个副作用函数有触发多个track的时候,我们执行的时候,要先将这些都删除,
下面分析一下代码执行流程是:

effect(() => {
  console.log('effect run')
  document.body.innerText = obj.ok ? obj.text : 'not'
})

执行

() => {
    cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()
  }

这里 cleanup第一次执行effectFn.deps为空没意义

然后
fn()执行
obj.ok 被读取为true
track执行
这个时候 bucket的存储结构是
obj->ok->[ fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

} ]
activeEffect.deps.push(deps)
这个时候activeEffect的deps是[ [ fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

} ] ]

acticeEffect 本身是函数,结构是
fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

}

然后 obj.text 被读取

track执行
这个时候 bucket的存储结构是
obj->ok->[ fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

} ]

obj->text->[ fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

} ]
activeEffect.deps.push(deps)
这个时候activeEffect的deps是[ [ fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

} ] , [fun(){

  cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()

} ] ]

一秒之后

setTimeout(() => {
  obj.ok = false
  setTimeout(() => {
    obj.text = 'hello vue3'
  }, 1000)
}, 1000)

trigger 执行
存储ok对应的函数执行,函数如下

() => {
    cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()
  }

当cleanup执行完后,bucket的中 ok和 text的副作用函数都被删除了
在这里插入图片描述
然后fun()执行,将ok的副作用函数重新添加,因为ok为false,这个时候text就不会再触发了,也就不会在存储副作用函数,

注意:set的forEach方法中如果同时删除,添加相同元素会造成无限循环
所以要创建一个新的set来执行副总用函数
因为执行副作用函数,先会调用cleanup清楚set中的数据,然后执行fn又会添加同样的副作用函数,便会造成无限循环

const effectsToRun = new Set()
  effects && effects.forEach(effectFn => effectsToRun.add(effectFn))
  effectsToRun.forEach(effectFn => effectFn())
  // effects && effects.forEach(effectFn => effectFn())

4.5 嵌套的effect与effect栈

这个的目标是要实现的是effect的嵌套,例如当数据变化时,要重新执行组件渲染函数,使页面数据发生改变,需要先改变父组件,再改变子组件

effect (()=>{
  F.render()
  effect(()=>{
  S.render()
  }
  )
})

``
必须改造上面的代码
```javascript
let temp1, temp2

effect(function effectFn1() {
  console.log('effectFn1 执行')
  effect(function effectFn2() {
    console.log('effectFn2 执行')
    temp2 = obj.bar
  })
  temp1 = obj.foo
})


let activeEffect
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    fn()
  }
  // activeEffect.deps 用来存储所有与该副作用函数相关的依赖集合
  effectFn.deps = []
  // 执行副作用函数
  effectFn()
}

上面的effect执行流程是:

  1. activeEffect= () => {
    cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn

    function effectFn1() {
    console.log(‘effectFn1 执行’)
    effect(function effectFn2() {
    console.log(‘effectFn2 执行’)
    temp2 = obj.bar
    })
    temp1 = obj.foo
    }()
    }

2.fu执行
activeEffect= () => {
cleanup(effectFn)
// 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
activeEffect = effectFn
() => {
cleanup(effectFn)
// 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
activeEffect = effectFn
function effectFn2() {
console.log(‘effectFn2 执行’)
temp2 = obj.bar
})
temp2 = obj.bar
}()
}
}
3.obj.bar收集副作用函数
这个时候activeEffect 是嵌套的副作用函数

4 obj.foor执行,收集副作用函数
obj.bar和obj.foor都收集obj.bar的副作用函数

当修改obj.foor的时候不会执行

改造,如下

// 用一个全局变量存储当前激活的 effect 函数
let activeEffect
// effect 栈
const effectStack = []

function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
    activeEffect = effectFn
    // 在调用副作用函数之前将当前副作用函数压栈
    effectStack.push(effectFn)
    fn()
    // 在当前副作用函数执行完毕后,将当前副作用函数弹出栈,并还原 activeEffect 为之前的值
    effectStack.pop()
    activeEffect = effectStack[effectStack.length - 1]
  }
  // activeEffect.deps 用来存储所有与该副作用函数相关的依赖集合
  effectFn.deps = []
  // 执行副作用函数
  effectFn()
}

每次fn执行之后,就会将activeEffect改为上一层的effectFn,如果没有上一层就为空,即effectStack为空,每次执行fneffectStack就退一次栈,保证每次track 添加的都是当前层级的effectFn

4.6 避免无限递归循环

这个要解决的问题是当,副作用函数中出现,即读取对象,又设置对象的情况,例如副作用函数中是: obj.num=obj.num+1,之前的代码会导致无限循环,
之前导致循环的代码如下:

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)

  const effectsToRun = new Set()
  effects && effects.forEach(effectFn => effectsToRun.add(effectFn))
  effectsToRun.forEach(effectFn => effectFn())
  // effects && effects.forEach(effectFn => effectFn())
}

分析一下流程:
obj.text=obj.text+1;
先读取了obj.text,那么就会,track会存储反应函数,
这个时候
activeEffect = effectFn
读取obj.text的fn还没执行完
activeEffect还没被置空
然后obj.text 被赋值
直接就执行了存储的effectFn,也就是全局的activeEffect
然后
activeEffect重新赋值
然后又obj.text 读取
存储又activeEffect
然后又obj.text被赋值,
。。。。。
就无限循环了

这其中的问题是activeEffect没置空之前,就又执行effectFn,导致存储的的
effectFn总是和activeEffect一样

改造如下:

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)

  const effectsToRun = new Set()
  effects && effects.forEach(effectFn => {
    if (effectFn !== activeEffect) {//刚存储的副作用函数,不能是已经存储的副作用函数
      effectsToRun.add(effectFn)
    }
  })
  effectsToRun.forEach(effectFn => effectFn())
  // effects && effects.forEach(effectFn => effectFn())
}

当存储的副作用函数effectFn和全局变量activeEffect一样说明,effect函数中fun没有执行完,就触发了trigger,所以不执行这个effectFn,

4.7 调度执行

调度执行是指,多次修改代理对象的某个值,只执行最后一次副作用函数,省略中间过程,Vue.js中连续修改多次响应式数据,只更新一次和这个原理差不多

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)

  const effectsToRun = new Set()
  effects && effects.forEach(effectFn => {
    if (effectFn !== activeEffect) {
      effectsToRun.add(effectFn)
    }
  })
  effectsToRun.forEach(effectFn => {
    if (effectFn.options.scheduler) {
      effectFn.options.scheduler(effectFn)
    } else {
      effectFn()
    }
  })
  // effects && effects.forEach(effectFn => effectFn())
}



const jobQueue = new Set()
const p = Promise.resolve()

let isFlushing = false
function flushJob() {
  if (isFlushing) return
  isFlushing = true
  p.then(() => {
    jobQueue.forEach(job => job())
  }).finally(() => {
    isFlushing = false
  })
}


effect(() => {
  console.log(obj.foo)
}, {
  scheduler(fn) {
    jobQueue.add(fn)
    flushJob()
  }
})

obj.foo++
obj.foo++

如代码 effect第二个参数是调度器,是一个函数,让用户来自定义执行副作用函数,trigger中判断如果有调度器,怎用调度器来执行副作用函数
如果没第一个参数
obj.foo++
obj.foo++
打印的结果是1 2 3 而使用了上面的代码结果是1 3,实现多次修改响应式数据,只触发一次副作用函数
那么如何办到的呢?
用jobQueue来存储每次修改obj.foo相同的effectFn函数,obj.foo++执行两次,
jobQueue.add(fn); flushJob()
也执行两次,但是因为set是不允许重复的,jobQueue中只存在一个effecFn
第一次obj.foo++ ,flushJob(),isFlushing值由默认的false变成ture
导致第二次obj.foo++,flushJob() 直接return了,
由于第一次是p.then是微任务,只有当所有同步代码执行玩才会执行 jobQueue.forEach(job => job())
所以第二次obj.foo++ 的调度器结束执行以后,才会在jobQueue.forEach(job => job()) 拿出存入的一个effectFn来执行,得到3这个值

问题汇总:

第四章 响应系统的作用与实现
4.1 响应式数据与副作用函数
(一)是什么是响应式数据和副作用函数?
响应式数据是当对象数据(设置)改变的时候,会执行读取数据的操作,读取数据操作的函数就是副作用函数

const obj={ text:"hello"} // 响应式数据

function effect() // 副作用函数
{
  document.body.innerText=obj.text
}

4.3 设计一个完善的响应式系统
(二)effect和activeEffect的作用是什么?
effect是注册副作用函数,即使副作用函数是一个匿名函数也可以被添加到bucket,
activeEffect是用于存储当前的副作用函数的全局变量,让收集副作用的函数更好的收集
(三)bucket的作用以及结构?
bucket是存储某个对象,对应的某个属性,对应的副作用函数。一个bucket有多个对象,
每个对象有多个属性,每个属性有多个副作用函数
WeakMap(对象)->Map(属性)->Set(副作用函数)
(四)不在副作用函数中读取对象属性,会被收集吗?
不会,必须在effect中执行副作用函数中读取对象属性的副作用函数才会被收集,
(五)当修改对象的属性的值的时候,会执行对应的副作用函数这个时候又会读取属性,还会收集吗?
不会,虽然执行副作用函数,但是track是收集activeEffect变量的值,没有在effect中执行副作用函数,无法将变量传递给activeEffect,所以无法收集,
注意这有个问题:如果有一个对象有两个属性都收集,那么修改第一个属性值,他会触发副作用函数,收集全局activeEffect,但是这个时候activeEffect是第二个属性的副作用函数,可以将副作用函数执行完后activeEffect置空,

// 存储副作用函数的桶
const bucket = new WeakMap()

// 原始数据
const data = { text: 'hello world',title:"名字" }
// 对原始数据的代理
const obj = new Proxy(data, {
  // 拦截读取操作
  get(target, key) {
    // 将副作用函数 activeEffect 添加到存储副作用函数的桶中
    track(target, key)
    // 返回属性值
    return target[key]
  },
  // 拦截设置操作
  set(target, key, newVal) {
    // 设置属性值
    target[key] = newVal
    // 把副作用函数从桶里取出并执行
    trigger(target, key)
  }
})

function track(target, key) {
  let depsMap = bucket.get(target)
  if (!depsMap) {
    bucket.set(target, (depsMap = new Map()))
  }
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, (deps = new Set()))
  }
  deps.add(activeEffect)
}

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  effects && effects.forEach(fn => fn())
}

// 用一个全局变量存储当前激活的 effect 函数
let activeEffect
function effect(fn) {
  // 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
  activeEffect = fn
  // 执行副作用函数
  fn()
  activeEffect=null
}

effect(() => {
  console.log('effect run')
  document.body.innerText = obj.text
})

effect(() => {
  console.log('effect run')
  document.body.innerText = obj.title
})

obj.text=11
obj.text=22

4.4 分支切换与cleanup
(六)什么是分支切换?如何实现?会不会出现上面收集两个对象属性,修改前一个属性,造成前一个属性收集后一个属性的副作用函数的问题?同一个属性有多个副作用又是什么情况呢?
(1)分支切换是一个优化性能的操作。
effect(() => {
console.log(‘effect run’)
document.body.innerText = obj.ok ? obj.text : ‘not’
})
希望obj.ok开始为true的时候,obj.text收集对应的副作用函数
当obj.ok更改为false,则obj.text不收集对应的副作用
(2)解决办法就是在执行副作用函数前,清除所有属性对应当前副作用函数,
每一个副作用函数,不管有多少个属性被设置,都只有一个effecFn, 当有多个属性被设置,他们会收集同一个effecFn,用effectFn.deps可以将effectFn收集的存储起来,在effectFn执行的时候将所有effectFn清除掉,执行effectFn又会收集全局的activeEffect,
(3) 不会,因为当修改属性的时候执行的是effectFn 和直接执行effct不同,执行effctFn会先将activeEffct设置为自己,这样再次触发读取操作,收集的依然是当前属性的effectFn,这个规避的上面代码中的bug
const effectFn = () => {
cleanup(effectFn)
// debugger
// 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
activeEffect = effectFn
fn()
}
(4)一个属性多个副作用函数,也是不影响,cleanup函数只删除,同一个effct函数中的effctFn中读取的属性的的副作用函数,每一个effct函数都会有不同的effcFn函数,
对象属性收集的

function cleanup(effectFn) { // 参数是当前effctFn
console.log(“effectFn”,effectFn)
for (let i = 0; i < effectFn.deps.length; i++) {
const deps = effectFn.deps[i];
deps.delete(effectFn) //删除set中的当前执行的effectFn函数
}
effectFn.deps.length = 0
}

(七)Set中在forEach中同时删除和添加一个值,会有什么问题?
会造成无限循环,解决方法就是用Set(set)直接变历结果

4.5 嵌套的effect与effect栈
(八)什么情况下需要effct嵌套?如何解决嵌套的问题?
(1)当一个组件中渲染另一个组件,就有嵌套发送,effect(()=>{ effect() })
(2)当执行外面的effect函数的时候activeEffect会是外面的effectFn,当执行里面的effect函数的时候,这个时候外面的还没收集activeEffect,而activeEffect改变为里面的effectFn,所以里面和外面都收集里面的effectFn,
应该设计一个栈才存储当前的所有的effectFn,activeEffect永远指向栈顶,执行完fun() 就退一个栈,将activeEffect向下移动,如果没有嵌套,effect执行完activeEffect会为空

4.6 避免无限递归循环
(九)当副作用函数中读取,又有设置同一个对象属性,会出现什么问题?如果是不同对象属性呢?如何用解决?
(1)会出现无限循环,原因是开始读取了,会触发track收集副作用,然后设置,会触发trigger执行当前收集的函数,然后收集的函数又触发了track,和trigger,一直循环下去
(2)解决方法就是判断当前的执行的副作用函数,是不是当前添加的副作用函数,如果是就表示当前存effct还没执行完,就执行了trigger函数,因为如果effect执行完了那么activeEffct会置空,如果是嵌套也effctFn和activeEffct不会相等
if (effectFn != activeEffect) {
effectsToRun.add(effectFn)
}
(3)如果是不同对象属性,不会造成无限循环,例如读取A,设置了B,会收集当前的effctFn函数,设置了B会,执行B的effctFn,B的effctFn和A的effctFn没有关系,所以无限循环必须是副作用函数中,同时读取和设置对象的同一个属性

4.7 调度执行
(十)什么是可调度性?调度器如何设计的?调度器options中的scheduler的作用?
(1)可调度性是指当trigger动词触发执行副作用函数的时候,有能力决定副作用函数执行的时机、次数以及方式,
(2)调度器是放在effct(fun,{})的第二个参数上,为一个对象。这个对象会添加到effectFn.options上,每一个effctFn有一个调度器对象,当trigger执行effctFn的时候,可以获得effectFn上的options。
(3)scheduler:传入的一个函数,当触发effectFn执行的时候,effctFn不直接执行,而是执行scheduler这个自定义的函数,他的参数是effectFn。例如:它可以让effectFn异步执行,

// =========================

const jobQueue = new Set() // 相同的函数只存储一次
const p = Promise.resolve()

let isFlushing = false
function flushJob() {
  if (isFlushing) return
  isFlushing = true
  p.then(() => {  // 微任务
    jobQueue.forEach(job => job())
  }).finally(() => {
    isFlushing = false
  })
}


effect(() => {
  console.log(obj.foo)
}, {
  scheduler(fn) {
    jobQueue.add(fn)// 相同的函数只存储一次
    flushJob()
  }
})

obj.foo++
obj.foo++
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值