链式调用和延迟执行

概述

工程化配置webpack中,在配置loader的时候,会看到能够写链式调用的写法,如下:

js 复制代码
config.module
  .rule('vue') // 创建一个名为 'vue' 的规则
    .test(/\.vue$/) // 规则的条件:匹配 .vue 文件
    .use('vue-loader') // 使用一个名为 'vue-loader' 的 loader
      .loader('vue-loader') // 指定 loader 的包名
      .end()
    .end()
  .rule('css') // 创建另一个名为 'css' 的规则
    .test(/\.css$/)
    .use('style-loader')
      .loader('style-loader')
      .end()
    .use('css-loader')
      .loader('css-loader');

这里实现类似链式调用的一个函数功能:有时候可能项目上需要插入多个任务,之间是链式执行的情况,通过链式调用来定义一个任务队列,这个队列可以混合立即执行的同步任务 和需要等待的异步任务(如定时器/异步任务) 。特别的是,它提供了一个 .waitFirst() 方法,可以将一个异步等待任务插入到整个队列的最前面 执行。最后调用 .execute() 来按顺序执行整个队列。

实现效果

任务:

js 复制代码
        // 任务
        createTask('A')
            .wait(2000).doSomething("第一件事")
            .wait(3000).doSomething("第二件事")
            .waitFirst(1000)
            .execute();
            
            
         

输出:

js 复制代码
Waited first for 1000 ms
Task A start
Waited for 2000 ms
Doing something in task 第一件事
Waited for 3000 ms
Doing something in task 第二件事

实现

js 复制代码
// 定义一个创建任务的函数,接受一个任务名称
function createTask(name) {
    // 初始化一个空数组,用于存储后续由各种方法添加的任务函数
    const taskList = []

    // 1. 首先,将一个"任务开始"的同步任务加入队列
    // 这是一个立即执行的同步任务,用于标记任务开始
    taskList.push(() => {
        console.log(`Task ${name} start`);
    })
    
    // 定义 wait 方法,它接受一个毫秒数 ms
    function wait(ms) {
        // 向任务队列尾部推送一个新的异步任务函数
        taskList.push(() => {
            // 这个任务返回一个 Promise,使其成为一个可等待的异步任务
            return new Promise((resolve) => {
                // 使用 setTimeout 实现等待
                setTimeout(() => {
                    console.log(`Waited for ${ms} ms`);
                    resolve(); // 等待完成后,解析 Promise,让队列继续执行下一个任务
                }, ms);
            });
        })
        // 返回 this(即 createTask 返回的对象),实现链式调用
        return this
    }

    // 定义 doSomething 方法,它接受一个消息 msg
    function doSomething(msg) {
        // 向任务队列尾部推送一个新的同步任务函数
        taskList.push(() => {
            console.log(`Doing something in task ${msg}`);
        })
        // 返回 this,实现链式调用
        return this
    }

    // 定义 waitFirst 方法,它接受一个毫秒数 ms
    // 这是关键方法,它与 wait 不同,将任务插入队列头部
    function waitFirst(ms) {
        // 使用 unshift 而不是 push,将任务插入到数组的最开头
        taskList.unshift(() => {
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(`Waited first for ${ms} ms`);
                    resolve();
                }, ms);
            });
        })
        // 返回 this,实现链式调用
        return this
    }

    // 定义 execute 方法,用于开始按顺序执行任务队列
    function execute() {
        // 使用立即执行的异步函数表达式 (IIFE) 来执行异步遍历
        (async function () {
            // 使用 for...of 循环按顺序遍历任务队列
            for (const task of taskList) {
                // 使用 await 等待当前任务执行完成
                // 如果任务是同步的(如 doSomething),会立即执行
                // 如果任务是异步的并返回 Promise(如 wait, waitFirst),会等待其 resolve 后再继续
                await task()
            }
        })() // 立即调用这个异步函数

        // 仍然返回 this,虽然通常 execute 是链式调用的终点,但保持了API的一致性
        return this
    }

    // 返回一个对象,暴露出的方法可以供外部链式调用
    // 注意:这里返回的方法闭包引用了内部的 taskList 数组,这就是它们能操作同一个队列的原因
    return {
        wait,
        doSomething,
        waitFirst,
        execute
    }
}

// 使用示例:创建一个名为 'A' 的任务
createTask('A')
    // 链式调用:定义等待2秒后做第一件事
    .wait(2000).doSomething("第一件事")
    // 链式调用:定义再等待3秒后做第二件事
    .wait(3000).doSomething("第二件事")
    // 关键操作:将"首先等待1秒"这个任务插入到整个队列的最前面
    .waitFirst(1000)
    // 开始执行整个定义好的任务队列
    .execute();
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端