这边文章主要面向准备着手看vue-next源码,但是无从下手的朋友
- 如何通过chrome + vscode debug Vue3 的测试案例
- reactivity 精简版(只包含了最基本的数据流逻辑)
- 非复刻源码,只注重怎么实现dataFlow
通过chrome + vscode debug Vue3源码
【博客地址】: shancw96.github.io/blogs/2020/…
开启chrome 调试界面 chrome://inspect
- 打开 chrome,并输入地址: chrome://inspect
- 选择 Open dedicated DevTools for Node
在 package.json – script 添加如下命令
... "scripts": { ... "test:debug": "node --inspect node_modules/.bin/jest --runInBand" }, ...
开始对测试案例进行debug
npm run test:debug <path_to_test>
example:debug reactivity 模块下的reactive.spec.ts
相对路径(vue-next 根目录):./packages/reactivity/__tests__/reactive.spec.ts
-
开启chrome://inspect设置
-
在测试文件或者源文件(独立模块)中添加
debugger
测试模块中添加
`npm run test:debug ./packages/reactivity/__tests__/reactive.spec.ts`
- 自动触发debug
96行乞丐版reactivity 奉上,辅助阅读源码
const isObject = val=> val !== null && typeof val === 'object' // 依赖存放targetMap //targetMap : object -> key -> Array<dep> let targetMap = new WeakMap() function reactive(target) { // 1. 判断是否为对象,proxy 只能代理对象 if(!isObject(target)) return target const proxy = new Proxy(target, { get, set }) return proxy } // proxy - get function get(target, key, receiver) { const res = Reflect.get(target, key, receiver) // 依赖收集 track(target, key) // proxy 只代理了当前层的key,如果key 对应的value 是嵌套的,那么需要进行对应的依赖收集 if(isObject(res)) { reactive(res) } return res } // proxy - set function set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver) trigger(target, key) return result } // 写在effect下的响应式数据会进行依赖收集(track) function effect(fn) { const effect = createReactiveEffect(fn) effect() return effect function createReactiveEffect(fn) { const effect = function reactiveEffect() { try { activeEffect = effect return fn() }finally { activeEffect = undefined } } effect.deps = [] return effect } } // 依赖收集函数 function track(object, key) { // 非effect下调用的 proxy.key不进行依赖收集 if (!activeEffect) { return } // 有副作用函数需要将副作用函数和当前对象的具体key相互关联 // 1.按照对象初始化分组 let depsMap = targetMap.get(object) if(!depsMap) { targetMap.set(object, depsMap = new Map()) } let dep = depsMap.get(key) if(!dep) { depsMap.set(key, dep = new Set()) } //2. key <-> Array<Effect> if(!dep.has(activeEffect)) { dep.add(activeEffect) activeEffect.deps.push(dep) } } // 依赖触发 function trigger(target, key) { const depsMap = targetMap.get(target) if(!depsMap.get(key)) { // 从没有被track return } const effects = new Set() // 将所有的非 activeEffect 加入到等待执行队列中 const add = effectsToAdd => { if(!effectsToAdd) return effectsToAdd.forEach(effect => { if(effect !== activeEffect) {// ? 为什么不能是activeEffect effects.add(effect) } }) } // 将depsMap中 key 对应的effect 复制一份,放到等待执行队列中 if(key !== void 0) { add(depsMap.get(key)) } //执行队列 effects.forEach(effect => effect()) }
简单测试
// -------test-------- // test const data = { msg: 'hey there', count: 1 } const proxyData = reactive(data) effect(() => { console.log('effect(msg)', proxyData.msg) }) proxyData.msg = 'hey there! i\'m here' proxyData.count = 2// effect(() => console.log('effect 2(count):', proxyData.count)) proxyData.count = 'should work' /** *effect(msg) hey there effect(msg) hey there! i'm here effect 2(count): 2 effect 2(count): should work */
写在最后:上述代码根据vue3源码进行大量删减,保留最基本的逻辑功能(依赖收集),会存在很多问题,只进行了基本类型的测试,勿杠。