Vue3.0源码学习——响应式原理(二)

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。

前言

回忆前篇 Vue3.0源码学习——响应式原理(一),学习了Vue3.0响应式API的使用以及 reactive 函数的源码,这篇紧跟上一篇将结合单步调试和源码进行探究

单步调试

写一个简单的例子

<body>
  <div id="app">
    <p>{{ state.counter }}</p>
  </div>
  <script>
    const app = Vue.createApp({
      setup() {
        const state = Vue.reactive({
          counter: 1
        })

        setInterval(() => {
          state.counter++
        }, 1000)

        Vue.watch(() => state.counter, () => {

        })

        return {
          state
        }
      }
    })

    app.mount('#app')
  </script>
</body>
复制代码
  • 打开调试,首先找到 reactive 函数 /packages/reactivity/src/reactive.ts单步进入返回的 createReactiveObject 函数

图片.png

  • 单步执行查看内部执行, Proxy 代理中 handelerbaseHandlers,就是在 reactive 中调用时传入的 mutableHandlers

图片.png

  • 找到 mutableHandlers 的位置 /packages/reactivity/src/baseHandlers.ts

图片.png

getter拦截

  • 其中的 getcreateGetter 函数,可以看到第一次 get 到了数据

图片.png

  • 此时查看调用栈,可以看到是在之前的例子中定义的 watch 中第一次获取数据

图片.png

  • 单步执行如果数据不是只读 !isReadonly 会走到 track 依赖收集函数,然后单步进入看一下内部执行

图片.png

  • 内部生成了一个依赖收集的Map对象 depsMap,会根据当前数据的 key 从全局的 targetMap 去取,第一次获取数据没有找到就会新建一个,value值 dep 就是收集到的依赖,然后执行到一个依赖跟踪函数 trackEffects 将当前数据的依赖 dep 传入

图片.png

  • trackEffects 会判断依赖中是否有组件更新函数,如果没有就会放进去

图片.png

  • getter操作会执行好几次,收集完了依赖就可以看一下在setter中会有怎样的操作,可以将getter中的断点取消

setter拦截

  • 将断点打在 createSetter 函数中,可以看到页面上已经渲染出了数据,因为例子中在 setInterval 改变了 counter 的值,所有走到了setter中,会执行到 trigger 触发组件更新函数

图片.png

  • 单步进入 trigger 看一下,首先会拿到当前数据收集的依赖 depsMap, 在依赖收集 dep 中放入组件更新函数

图片.png

  • 然后走到 triggerEffects 触发真正的组建更新函数,会将收集到依赖的地方进行相应的操作

图片.png

  • 继续往下执行可以看到页面也更新了

图片.png

reactive函数执行流程图

根据源码分析和单步调试可以简单整理了一个流程图

图片.png

猜你喜欢

转载自juejin.im/post/7063369228258115620