Vue 源码学习-响应式系统(1)

Vue 的响应式系统核心在于响应式对象的属性与 effect 副作用函数之间建立的依赖关系。

ref 的实现

初定义

// ref.ts import { activeSub } from "./effect"; export class RefImpl { _value; constructor(val: any) { this._value = val; } get value() { return this._value; } set value(newVal) { this._value = newVal; activeSub?.() } } export function ref(val: any) { return new RefImpl(val); }
// effect.ts export let activeSub: Function| undefined = undefined export function effect(fn: Function){ activeSub = fn fn?.() activeSub = undefined }

问题1:使用时,如果有多个 effect 执行呢? 1.解决多个effect问题.png 此时必然只会执行最后一个 effect 中的函数。

解决:引入链表,通过链表收集多个 effect, 这里顺便改造 effect 中的逻辑,在 RefImpl类中加入头节点和尾节点概念,收集多个 effect。在响应式数据改变时,遍历链表以此执行多个 effect 接受的函数。

// effect.ts export let activeSub: ReactiveEffect | undefined = undefined export function effect(fn: Function, options: any){ const e = new ReactiveEffect(fn) Object.assign(e, options) e.run() } export class ReactiveEffect{ constructor(public fn: Function){} run(){ activeSub = this try{ return this.fn() }finally{ activeSub = undefined } } notify(){ this.scheduler() } scheduler(){ this.run() } }
// system.ts import { ReactiveEffect } from "./effect"; export interface Link { sub: ReactiveEffect; preSub: Link | undefined; nextSub: Link | undefined; }
// ref.ts import { activeSub } from "./effect"; import { Link } from "./system"; export class RefImpl { _value; subs: Link | undefined; subsTail: Link | undefined constructor(val: any) { this._value = val; } get value() { /** * 收集依赖 */ if(activeSub){ const newLink: Link = { sub: activeSub, preSub: undefined, nextSub: undefined } if(this.subsTail){ this.subsTail.nextSub = newLink newLink.preSub = this.subsTail this.subsTail = newLink }else{ this.subs = newLink this.subsTail = newLink } } return this._value; } set value(newVal) { this._value = newVal; let link = this.subs const queueEffect = [] while(link){ queueEffect.push(link.sub) link = link.nextSub } queueEffect.forEach(effect=>{ effect?.notify() }) } } export function ref(val: any) { return new RefImpl(val); }

Comments(0)

Please login to comment

No comments yet. Be the first to comment!