Skip to content

什么是依赖有效性呢

effect 的执行可能会因为条件判断或逻辑不同发生变化,导致部分依赖在执行过程中不再需要。 如果这些不再需要的依赖没有被正确移除,就会导致不必要的重新计算和性能问题。

  • 内存泄漏: 不需要的链表节点一直存在
  • 不必要的更新: effect 不依赖某个 ref 了, 但是这个 ref 依然会触发 effect 的重新执行

情况 1: 条件型依赖

html

<body>
<div id="app"></div>
<button id="flagBtn">update flag</button>
<button id="nameBtn">update name</button>
<button id="ageBtn">update age</button>


<script type="module">
  import {ref, effect} from '../dist/reactivity.esm.js'

  const flag = ref(true)
  const name = ref('zhangsan')
  const age = ref(12)

  effect(() => {
    console.count('effect')
    if (flag.value) {
      app.innerHTML = `姓名, ${name.value}!`
    } else {
      app.innerHTML = `变量, ${age.value}!`
    }
  })

  flagBtn.onclick = () => {
    flag.value = !flag.value
  }

  nameBtn.onclick = () => {
    name.value = name.value + Math.random()
  }

  ageBtn.onclick = () => {
    age.value = age.value + 1
  }
</script>
</body>

目前 flagnameage 三个变量都被 effect 收集为依赖,但实际上 nameage互斥的:

  • flagtrue 时,effect 只关心 name
  • flagfalse 时,effect 只关心 age

异常情况分析

  1. effect 的依赖链表里已找不到 name 节点,当前只剩 flag → age

  2. 然而 name 的订阅链表里仍保留着指向该 effect 的节点

异常结果: effect 的依赖链表中没有 name 节点, 但是 name 依赖链表中依然有 effect 节点

一步步拆解

步骤示意图说明
① 首次执行收集 flag,建立 link1
② 进入 if 分支flagtrue,继续收集 name,建立 link2
③ 点击按钮更新 flageffect 重新运行,depsTail 被重置为 undefined,准备重新收集
④ 复用 flag 节点检查到 link1 可复用,depsTail 指向 link1flag 现为 false
⑤ 收集新依赖 age进入 else 分支,新建 link3 并追加到 deps 尾部

根因

  • link2effectdeps 链表中被移除, 但是在 namesubs 链表中依然存在
  • name 依然会触发 effect 的重新执行

最后更新时间: