vue3-12-剖析vue3 Reactivity 源代码 v2

66 阅读3分钟

梳理流程

  • 判断是不是对象,如果不是对象就直接返回。
  • 重复代理如果代理了就不在代理了
  • 对不同类型进行proxy
  • Weakup 做缓存
  • 取值的时候【get】的时候会对数组类型单独处理 baseHandler.ts,对ref进行处理
  • set basehandler 设置值的时候也会对ref单独的处理 数组判断是新增还是修改。
  • effect 副作用函数
    • if(isEffect(fn)) 如果传进来的是effect fn = fn.raw 不需要effect只需要原来的函数 如何判断__isEffect
    • 如果是effect 就拿着 fn.raw 在创建一个
    • let effect1 = effect(()=>{}) let effect2 = effect(effect1) effect1 == effect2 // false 就拿着 fn.raw 在创建一个 createReactiveEffect(fn, options)
    • if(!options.lazy){ effect() } // 如果不是懒加载上来就执行
    • createReactiveEffect
      • 创建一个响应式的effect
      • 浅表的说会给effect 增加一些属性
        • effect.id = ++uid // 唯一的标识
        • effect.allowRecurse=!!options.allowRecurse // 是否允许运行effect重复执行
        • effect.__isEffect // 是不是effect
        • effect.active // 当前effect是不是激活的状态
        • effect.raw // effect对应的原函数
        • effect.deps // effect对应了哪些属性 每个属性会做依赖收集放在外边的变量相当于放到自身了 deps[dep = new Set()] // effect(()=>{state.name;state.age}); // 可以说name和age依赖了effect 如果同一个属性已经包含过相同的effect就不要在保存了依赖了。
        • cleanup(effect) // 每次重新收集依赖,每次重新执行effect都会重新取值,那么调用get方法,重新进行依赖收集。 为什么每次重新都需要收集?
        • effect默认没写lazy 就会默认执行一次
            // track
            const state = reactive({name:'pwd', age: ''});
            effect(() => {
                if(state.name === 'pwd') {
                    console.log(state.age);
                }
            }) // 默认第一次 render
        
            state.age = 1; // 第二次 render 
            state.name = 'aaa'; // 三次 render 因为如果 这里改成了 'aaa' !== 'pwd' 造成age不可达所以后面的也就不用执行了。
            state.age = 200; // 上面改了就不执行了 所以需要 cleanup(effect)  清理一下 因为不知道下一次要不要依赖了所以需要清理一下
        
            effect执行几次?
        
            // trigger
            const sttae = reactive({name:1});
            effect(()=>{
                state.name;
            })
            state.name = 123;
            // triger 是如何触发的。
        
            // 流程
            1. fn 是否是effect
            2. 如果是把effect 的原函数拿出来 fn.raw
            3. 创建effect 注意不管有没有raw每次创建的都是新的
            4. 如果lazy不是true就立即执行。
            5. 把当前的effect放到栈里面来
            6. cleanup 就是把 deps[i].delete(effect)  // 当前收集过的删掉 i 对应着effect
            7. 走到track流程
            8. 修改属性 走trigger triigger 和 track一个包 会从 deps上把目标对象拿出来拿到对应属性对应的effect执行它
            9. 去重复防止重复执行effect
            10. 是不是清理的清空所有的effect
            11. 是不是访问的length 数组特殊处理
            12. 收到effects 统一的执行
            13. effects.forEach  所有的内容都执行一下run
            14. run 看一下effect.options.ontrigger 是否有 ontrigger 如果有就调用 ontrigger
            15. 如果有scheduler 就调用 scheduler
            16. 如果  scheduler 都没有才会让 effect去执行
            带有scheduler的effect
            const sttae = reactive({name:1});   
            effect(()=>{state}, {
                scheduler: (effect) => { // 如果有scheduler就会调用scheduler 不会让effect去执行了
                    console.log("up") // 走我们自己的更新逻辑
                }
            }) 
            state.name = 1;
            17. effect用作watchAPI 比较多一些 watch基于effect实现的 组件也是基于effect的
        
        • effect.options