优化effect stop功能,附全流程断点调试视频

前言

本文是 Vue3 源码实战专栏的第 6 篇。

第三篇 完善effect功能 中实现了stop方法,本篇文章完善stop方法,并通过断点调试来完整解析整个流程。

修改单测

在原本的基础上,修改effectstop测试用例。

it("stop"() => {
  let dummy;
  const obj = reactive({ prop: 1 });
  const runner = effect(() => {
    dummy = obj.prop;
  });
  obj.prop = 2;
  expect(dummy).toBe(2);
  stop(runner);

  // obj.prop = 3;
  obj.prop++;
  expect(dummy).toBe(2);

  // stopped effect should still be manually callable
  runner();
  expect(dummy).toBe(3);
});

运行单测yarn test effect

优化effect stop功能,附全流程断点调试视频

报错分析

简单分析一下报错的原因。

obj.prop++可以理解成obj.prop = obj.prop + 1,存在getset两个操作,触发get操作会重新收集依赖,导致stopcleanupEffect方法删除所有effect失效。

实现

知道了根本原因是先触发get操作重新执行了effect中函数,也就是调用了track方法,那需要完善的逻辑应该这个方法入手。我们可以定义一个全局变量shouldTrack来判断是否需要进行track操作。

let reactiveEffect;
let shouldTrack;  // 定义

export function track(target, key{
  ...
 if(!shouldTrack) return // 直接return不进行依赖收集
  if (!reactiveEffect) return;
  dep.add(reactiveEffect);
  reactiveEffect.deps.push(dep);
}

进行赋值的时候触发set操作,执行trigger函数,最终调用的是 Class 类ReactiveEffectrun方法。run方法中原本是直接返回了入参函数的执行结果,这里就需要判断一下stop的情况,可以依据active来判断。

如果是调用了stop方法之后,active赋值为false,这时候直接返回fn

如果没有调用stop方法,先将shouldTrack设为true,表示可以进行track调用,然后执行fn,并将执行结果返回,但是在返回之前需要重置操作,将shouldTrack设置成false,因为如果在遇到stop之后,run函数中会直接return,不会将shouldTrack设为true,那在track时,就会走!shouldTrack直接return不再收集依赖。

run() {
  if (!this.active) {
    return this._fn();
  }

  shouldTrack = true;
  reactiveEffect = this;

  const result = this._fn();
  shouldTrack = false;

  return result;
}

重构

trackshouldTrackreactiveEffect的边界判断,可以提到track函数体内顶部,单独封装一个函数合成这两个判断。

依赖收集这儿可以优化的点,当dep中存在的reactiveEffect就不再重复收集了。

export function track(target, key{
  if (!isTracking()) return;

  ...

  if (dep.has(reactiveEffect)) return;
  dep.add(reactiveEffect);
  reactiveEffect.deps.push(dep);
}

function isTracking({
  return shouldTrack && reactiveEffect !== undefined;
}

调试

修改一下单测,用更简单的单测来通过调试清晰看一下上述流程。

it("stop"() => {
  let dummy;
  const obj = reactive({ prop: 1 });
  const runner = effect(() => {
    dummy = obj.prop;
  });
  stop(runner);
 
  obj.prop++;
  expect(dummy).toBe(1);
});

这里通过一个视频讲解来更形象的了解。

原文始发于微信公众号(前端一起学):优化effect stop功能,附全流程断点调试视频

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/191296.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!