返回顶部
首页 > 资讯 > 精选 >vue3调度器effect的scheduler功能怎么实现
  • 164
分享到

vue3调度器effect的scheduler功能怎么实现

2023-07-04 18:07:40 164人浏览 安东尼
摘要

本文小编为大家详细介绍“vue3调度器effect的scheduler功能怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue3调度器effect的scheduler功能怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入

本文小编为大家详细介绍“vue3调度器effect的scheduler功能怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue3调度器effect的scheduler功能怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

一、调度执行

说到scheduler,也就是vue3的调度器,可能大家还不是特别明白调度器的是什么,先大概介绍一下。

可调度性是响应式系统非常重要的特性。首先我们要明确什么是可调度性。所谓可调度性,指的是当trigger 动作触发副作用函数重新执行时,有能力决定副作用函数执行的时机、次数以及方式。

有了调度函数,我们在trigger函数中触发副作用函数重新执行时,就可以直接调用用户传递的调度器函数,从而把控制权交给用户。

举个栗子:

const obj = Reactive({ foo: 1 });effect(() => {  console.log(obj.foo);})obj.foo++;obj.foo++;

首先在副作用函数中打印obj.foo的值,接着连续对其执行两次自增操作,输出如下:

   1
   2
   3

由输出结果可知,obj.foo的值一定会从1自增到3,2只是它的过渡状态。如果我们只关心最终结果而不关心过程,那么执行三次打印操作是多余的,我们期望的打印结果是:

   1
   3

那么就考虑传入调度器函数去帮助我们实现此功能,那由此需求,我们先来实现一下scheduler功能。

二、单元测试

首先还是藉由单测来梳理一下功能,这是直接从vue3源码中粘贴过来对scheduler的单测,里面很详细的描述了scheduler的功能。

it('scheduler', () => {  let dummy;  let run: any;  const scheduler = jest.fn(() => {    run = runner;  });  const obj = reactive({ foo: 1 });  const runner = effect(    () => {      dummy = obj.foo;    },    { scheduler },  );  expect(scheduler).not.toHaveBeenCalled();  expect(dummy).toBe(1);  // should be called on first trigger  obj.foo++;  expect(scheduler).toHaveBeenCalledTimes(1);  // should not run yet  expect(dummy).toBe(1);  // manually run  run();  // should have run  expect(dummy).toBe(2);});

大概介绍一下这个单测的流程:

  • 通过 effect 的第二个参数给定的一个对象 { scheduler: () => {} }, 属性是scheduler, 值是一个函数;

  • effect 第一次执行的时候, 还是会执行 fn;

  • 当响应式对象被 set,也就是数据 update 时, 如果 scheduler 存在, 则不会执行 fn, 而是执行 scheduler;

  • 当再次执行 runner 的时候, 才会再次的执行 fn.

三、代码实现

那接下来就直接开始代码实现功能,这里直接贴出完整代码了,// + 会标注出新增加的代码。

class ReactiveEffect {  private _fn: any;  // + 接收scheduler  // + 在构造函数的参数上使用public等同于创建了同名的成员变量  constructor(fn, public scheduler?) {    this._fn = fn;  }  run() {    activeEffect = this;    return this._fn();  }}// * ============================== ↓ 依赖收集 track ↓ ============================== * //// * targetMap: target -> keyconst targetMap = new WeakMap();// * target -> key -> depexport function track(target, key) {  // * depsMap: key -> dep  let depsMap = targetMap.get(target);  if (!depsMap) {    targetMap.set(target, (depsMap = new Map()));  }  // * dep  let dep = depsMap.get(key);  if (!dep) {    depsMap.set(key, (dep = new Set()));  }  dep.add(activeEffect);}// * ============================== ↓ 触发依赖 trigger ↓ ============================== * //export function trigger(target, key) {  let depsMap = targetMap.get(target);  let dep = depsMap.get(key);  for (const effect of dep) {    // + 判断是否有scheduler, 有则执行,无则执行fn    if (effect.scheduler) {      effect.scheduler();    } else {      effect.run();    }  }}let activeEffect;export function effect(fn, options: any = {}) {  // + 直接将scheduler挂载到依赖上  const _effect = new ReactiveEffect(fn, options.scheduler);  _effect.run();  return _effect.run.bind(_effect);}

代码实现完成,那接下来看一下单测结果。

vue3调度器effect的scheduler功能怎么实现

四、回归实现

好,现在我们再回到最初的栗子????,在上面scheduler基础上,完成现有需求,继续看一下对此需求的单测。

it('job queue', () => {  // 定义一个任务队列  const jobQueue = new Set();  // 使用 Promise.resolve() 创建一个 Promise 实例,我们用它将一个任务添加到微任务队列  const p = Promise.resolve();  // 一个标志代表是否正在刷新队列  let isFlushing = false;  function flushJob() {    // 如果队列正在刷新,则什么都不做    if (isFlushing) return;    // 设置为true,代表正在刷新    isFlushing = true;    // 在微任务队列中刷新 jobQueue 队列    p.then(() => {      jobQueue.forEach((job: any) => job());    }).finally(() => {      // 结束后重置 isFlushing      isFlushing = false;      // 虽然scheduler执行两次,但是由于是Set,所以只有一项      expect(jobQueue.size).toBe(1);      // 期望最终结果拿数组存储后进行断言      expect(logArr).toEqual([1, 3]);    });  }  const obj = reactive({ foo: 1 });  let logArr: number[] = [];  effect(    () => {      logArr.push(obj.foo);    },    {      scheduler(fn) {        // 每次调度时,将副作用函数添加到 jobQueue 队列中        jobQueue.add(fn);        // 调用 flushJob 刷新队列        flushJob();      },    },  );  obj.foo++;  obj.foo++;  expect(obj.foo).toBe(3);});

在分析上段代码之前,为了辅助完成上述功能,我们需要回到trigger中,调整一下遍历执行,为了让我们的scheduler能拿到原始依赖。

for (const effect of dep) {  // + 判断是否有scheduler, 有则执行,无则执行fn  if (effect.scheduler) {    effect.scheduler(effect._fn);  } else {    effect.run();  }}

再观察上面的单测代码,首先,我们定义了一个任务队列jobQueue,它是一个Set数据结构,目的是利用Set数据结构的自动去重功能。

接着我们看调度器scheduler的实现,在每次调度执行时,先将当前副作用函数添加到jobQueue队列中,再调用flushJob函数刷新队列。

然后我们把目光转向flushJob函数,该函数通过isFlushing标志判断是否需要执行,只有当其为false 时才需要执行,而一旦flushJob函数开始执行,isFlushing标志就会设置为true,意思是无论调用多少次flushJob函数,在一个周期内都只会执行一次。

需要注意的是,在flushJob内通过p.then将一个函数添加到微任务队列,在微任务队列内完成对jobQueue的遍历执行。

整段代码的效果是,连续对obj.foo执行两次自增操作,会同步且连续地执行两次scheduler调度函数,这意味着同一个副作用函数会被jobQueue.add(fn)添加两次,但由于Set数据结构的去重能力,最终jobQueue中只会有一项,即当前副作用函数。

类似地,flushJob也会同步且连续执行两次,但由于isFlushing标志的存在,实际上flushJob函数在一个事件循环内只会执行一次,即在微任务队列内执行一次。

当微任务队列开始执行时,就会遍历jobQueue并执行里面存储的副作用函数。由于此时jobQueue队列内只有一个副作用函数,所以只会执行一次,并且当它执行时,字段obj.foo的值已经是3了,这样我们就实现了期望的输出。

再跑一遍完整流程,来看一下单测结果,确保新增代码不影响以往功能。

vue3调度器effect的scheduler功能怎么实现

测试结束完以后,由于job queue是一个实际案例单测,所以我们将其抽离到examples下面的testCase里,建立jobQueue.spec.ts

读到这里,这篇“vue3调度器effect的scheduler功能怎么实现”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网精选频道。

--结束END--

本文标题: vue3调度器effect的scheduler功能怎么实现

本文链接: https://lsjlt.com/news/346717.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • vue3调度器effect的scheduler功能怎么实现
    本文小编为大家详细介绍“vue3调度器effect的scheduler功能怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue3调度器effect的scheduler功能怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入...
    99+
    2023-07-04
  • vue3调度器effect的scheduler功能实现详解
    目录一、调度执行二、单元测试三、代码实现四、回归实现五、结语一、调度执行 说到scheduler,也就是vue3的调度器,可能大家还不是特别明白调度器的是什么,先大概介绍一下。 可...
    99+
    2022-12-08
    vue3调度器effect scheduler effect scheduler
  • Goland协程调度器scheduler如何实现
    本篇内容主要讲解“Goland协程调度器scheduler如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Goland协程调度器scheduler如何实现”吧!1. 调度器schedule...
    99+
    2023-06-30
  • 一文理解Goland协程调度器scheduler的实现
    目录1. 调度器scheduler的作用2. GMP模型3. 调度机制1. 调度器scheduler的作用 我们都知道,在Go语言中,程序运行的最小单元是gorouines。 然而程...
    99+
    2024-04-02
  • hadoop Yarn调度器Scheduler的特点是什么
    这篇文章主要讲解了“hadoop Yarn调度器Scheduler的特点是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“hadoop Yarn调度器Scheduler的特点是什么”吧!概...
    99+
    2023-06-03
  • C#怎么实现调用浏览器的功能
    本篇内容主要讲解“C#怎么实现调用浏览器的功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#怎么实现调用浏览器的功能”吧!C#调用浏览器之调用IE:System.Diagnostics.Pr...
    99+
    2023-06-17
  • Python怎么调用百度AI实现颜值评分功能
    本篇内容主要讲解“Python怎么调用百度AI实现颜值评分功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python怎么调用百度AI实现颜值评分功能”吧!一、调用百度接口进行人脸属性识别安装...
    99+
    2023-06-21
  • vue3怎么使用vuedraggable实现拖拽功能
    这篇文章主要介绍了vue3怎么使用vuedraggable实现拖拽功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue3怎么使用vuedraggable实现拖拽功能文章都会有所收获,下面我们一起来看看吧。n...
    99+
    2023-06-29
  • Python调用百度AI实现颜值评分功能
    目录一、调用百度接口进行人脸属性识别二、根据年龄和性别对颜值进行评价三、批量识别人脸属性四、自定义窗口语音播报颜值得分五、明星颜值评价一、调用百度接口进行人脸属性识别 安装好baid...
    99+
    2024-04-02
  • JS怎么实现进度条顺滑功能
    本篇内容主要讲解“JS怎么实现进度条顺滑功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JS怎么实现进度条顺滑功能”吧!进度条不顺滑相信大多前端同学都自己写过音频、视频播放器,实现并不复杂。最...
    99+
    2023-06-20
  • 易语言怎么实现进度条功能
    在易语言中,可以通过循环控制和延时操作来实现进度条功能。下面是一个简单的示例代码:```// 设置进度条的长度const Progr...
    99+
    2023-08-17
    易语言
  • vue3全局组件自动注册功能怎么实现
    本篇内容主要讲解“vue3全局组件自动注册功能怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue3全局组件自动注册功能怎么实现”吧!vue3全局组件自动注册建文件需要在src/comp...
    99+
    2023-07-06
  • Vue3封装登录功能的两种实现
    目录方法一: 使用用户名和密码进行登录方法二: 使用手机验证码登录方法一: 使用用户名和密码进行登录 封装代码: <template> <el-form ...
    99+
    2024-04-02
  • Vue3父子组件互调怎么实现
    今天小编给大家分享一下Vue3父子组件互调怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、父组件调用子组件方法下面...
    99+
    2023-06-30
  • javascript怎么实现类似百度分享功能
    百度分享是一个非常流行的社交分享插件,允许网站的访问者方便地分享网站上的内容。这个功能非常受欢迎,因为它允许用户快速地将他们所喜欢的内容分享到不同的社交网络,例如微信、微博、QQ等。但是,你知道吗?你也可以使用javascript实现类似的...
    99+
    2023-05-14
  • Android怎么实现阅读进度记忆功能
    小编给大家分享一下Android怎么实现阅读进度记忆功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!具体内容如下用户提了一个要求,要求保存他的阅读进度,然后在他...
    99+
    2023-05-30
    android
  • Vue3中的Teleport功能怎么使用
    这篇文章主要介绍“Vue3中的Teleport功能怎么使用”,在日常操作中,相信很多人在Vue3中的Teleport功能怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3中的Teleport功能怎...
    99+
    2023-07-02
  • Django怎么实现带进度条的倒计时功能
    这篇文章主要介绍“Django怎么实现带进度条的倒计时功能”,在日常操作中,相信很多人在Django怎么实现带进度条的倒计时功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Django怎么实现带进度条的倒计...
    99+
    2023-07-06
  • C#调用百度翻译API实现一个翻译功能
    前言 虽然百度翻译相对于谷歌翻译在准确性方面还有很大的提升空间,但网络的现实情况及百度翻译接口的免费易用性方面让我们选择百度翻译接口。下面来一起看看详细的步骤吧 方法如下 appId...
    99+
    2024-04-02
  • uniapp调用百度语音实现录音转文字功能
    经历三天时间各种遇到困难 之后终于实现了这个功能,参照网上了许多文章 才找到一个能正常实现的方法,网上能找到的例子都不起作用,相信很多人困惑在这,为了避免别人出现这种情况,我分享我的...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作