巨拼门店系统
93.52M · 2026-04-07
// 实例
const state = reactive({ name: "zoyi" });
const aliasName = computed(() => {
console.log("getter 执行");
return "**" + state.name;
});
effect(() => {
console.log("外层 effect 执行");
console.log(aliasName.value);
});
state.name = "star zoyi";
export class ComputedRefImpl {
constructor(getter: () => any) {
this.effect = new ReactiveEffect(getter, () => {
//...
});
}
}
get value() {
// 外层 effect 读取计算属性时,把外层 effect 记到本 ref 的 dep 上
this.trackComputed();
if (this._dirty === DirtyLevels.Dirty) {
this._dirty = DirtyLevels.NoDirty;
this._value = this.effect.run();
}
return this._value;
}
/** 收集「谁依赖了这个计算属性」 */
private trackComputed() {
if (!activeEffect) {
return;
}
this.dep ??= createDep(() => {
this.dep = undefined;
}, "computed");
trackEffect(activeEffect, this.dep);
}
_dirty 默认是脏,改为不脏,并执行 内部 effect.run()(即包含 computed 的 getter方法的运行器)。return 中执行 state.name 触发 name 属性的 get,将此时 activeEffect = 内层effect,收集为依赖。返回 name = zoyi。return 计算后属性 @zoyi,将值缓存到 aliasName._value 上,aliasName.value 的 get value 执行完毕,并返回 _value。此时关系是:
执行 state.name = "star zoyi" state.name 发生改变,触发 name 的 setter。
set(target, key, value, recevier) {
let oldValue = target[key];
let result = Reflect.set(target, key, value, recevier);
// 只有新旧值不一样才会触发更新
if (oldValue !== value) {
trigger(target, key, value, oldValue);
}
return result;
}
新旧值不一样,触发 trigger,执行收集到的内层 effect 的 scheduler。
_dirty 设置为脏。constructor(getter: () => any) {
// 不在此构造函数里立即 run:首次访问 .value 时再求值,实现惰性。
// scheduler:依赖变更时不立刻重算,只标脏并通知「读过我的人」去更新。
this.effect = new ReactiveEffect(getter, () => {
if (this._dirty === DirtyLevels.NoDirty) {
this._dirty = DirtyLevels.Dirty;
}
if (this.dep) {
triggerEffects(this.dep); // aliasName.dep
}
});
}
_dirty 为脏 → 执行 this.effect.run() → 打印 getter 执行,读到新 state.name,得到 @star zoyi,缓存进 _value,再标不脏。state.name = "star zoyi" state.name 发生改变,触发 name 的 setter。refreshComputed -> 发现 _dirty 为脏,先清脏 → 执行 this.effect.run() → 打印 getter 执行,读到新 state.name,得到 @star zoyi,缓存进 _value。constructor(getter: () => any) {
this.effect = new ReactiveEffect(getter, () => {
// 3.5 风格:先置脏并同步重算,再通知下游(顺序与官方包一致)
this._dirty = DirtyLevels.Dirty;
this.refreshComputed();
if (this.dep) {
triggerEffects(this.dep); // 再执行外层 effect.run
}
});
}
/**
* 若当前为脏,则执行内层 effect(getter),更新 _value 并清脏。
*/
private refreshComputed() {
if (this._dirty !== DirtyLevels.Dirty) {
return;
}
this._dirty = DirtyLevels.NoDirty;
this._value = this.effect.run(); // 先执行 getter
}
_value 中获取并返回。get value() {
// 收集计算属性(aliasName)的依赖,再保证缓存最新
this.trackComputed();
this.refreshComputed(); // _dirty 为不脏直接返回
return this._value; // 已经计算过新的属性了,直接从_value中获取
}
watch(
{ state.name }, // source
(prev, next, onCleanup) => { //cb
console.log("触发回调函数")
onCleanup(() => {
console.log("清理副作用函数");
});
},
{
immediate: false, // 立即执行一次
deep: false // 是否深度
});
source 发生变化,触发 cb 的执行
即 watch 需要实现:完成 source (必须是响应式)对某个 effect 进行收集,在触发 scheduler 时,将 cb 加入到其中,将新旧值传入 cb 中。
function watch(source, cb, options?) {
const { immediate = false, deep = false } = options;
const getter = createWatchGetter(source, deep);
let oldValue;
let cleanup;
// 初始化 effect,值变化时进行更新操作
const _effect = new ReactiveEffect(getter, () => {
const newValue = _effect.run(); // 获得最新的值
if (cleanup) {
cleanup();
cleanup = undefined;
}
cb(newValue, oldValue, (fn) => {
cleanup = fn;
});
oldValue = newValue;
});
oldValue = _effect.run();
// 立马执行一次 cb
if (immediate) {
cb(oldValue, undefined, (fn) => {
cleanup = fn;
});
}
return () => {
if (cleanup) {
cleanup();
cleanup = undefined;
}
stopEffect(_effect);
};
}
createWatchGetter:将 source 变为可执行的 getter,支持对 source 中的响应式属性进行依赖收集
function createWatchGetter(source: unknown, deep: boolean): () => unknown {
if (isRef(source)) {
return () => (source as { value: unknown }).value;
}
if (typeof source === "function") {
return source as () => unknown;
}
if (isArray(source)) {
return () =>
(source as unknown[]).map((s) => {
if (isRef(s)) {
return (s as { value: unknown }).value;
}
if (typeof s === "function") {
return (s as () => unknown)();
}
return s;
});
}
if (isReactive(source)) {
// deep 为 true 则深度,否则只一层
const maxDepth = deep ? undefined : 1;
return () => traverse(source, maxDepth);
}
return () => source;
}
清理函数:onCleanup 是回调的第三个参数,用来注册「下一次将要执行回调之前」或「停止时」会先执行的清理函数。
// 示例
watch(
() => state.id,
(id, oldId, onCleanup) => {
let cancelled = false;
onCleanup(() => {
cancelled = true;
});
fetch(`/api/user/${id}`).then((res) => {
if (!cancelled) {
state.user = res;
}
});
},
);
停止:watch 的返回值可以返回 stopEffect
/**
* 停止副作用:从各 dep 中移除并清空依赖列表,之后不再被 trigger。
*/
export function stopEffect(effect: ReactiveEffect) {
if (!effect.active) {
return;
}
effect.active = false; // 激活状态改为 false
const deps = effect.deps;
for (let i = 0; i < deps.length; i++) { // 并清理 effect 上的 deps
cleanDepEffect(deps[i], effect);
}
effect.deps.length = 0;
}
选项api:flush
我的MCP工具被下载了5000+次/周,从0到变现我做对了什么?
AI 周刊【2026.03.30-04.05】:Anthropic 史诗级乌龙、OpenAI 万亿狂奔、AI 伦理审查
2026-04-07
2026-04-07