Skip to content

消除异步执行器

任务执行的洋葱模型【渡一教育】_哔哩哔哩_bilibili 受该视频启发,实现以下异步执行器:

ts
/** 创建异步运行器 */
export const createAsyncRunner = () => {
  const tasks = [];
  const add = (task) => {
    tasks.push(task);
  };

  const start = () => {
    if (tasks.length > 0) {
      _runTask(tasks[0]);
    }
  };

  const _runTask = async (task) => {
    try {
      await task();
      tasks.shift();
      if (tasks.length > 0) {
        _runTask(tasks[0]);
      }
    } catch (error) {
      console.error(error);
    }
  };

  return {
    start,
    add,
  };
};

可以像如下代码,将所有任务(无论异步还是同步)按照添加顺序依次执行,并且会等待之前的异步任务执行完毕:

ts
/** 异步任务1 */
const asyncTask1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Task 1 completed");
    }, 200);
  });
};

/** 异步任务2 */
const asyncTask2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Task 2 completed");
    }, 100);
  });
};

runner.add(asyncTask1);
runner.add(asyncTask2);
runner.start(); // 200ms后完成asyncTask1,再经过100ms完成asyncTask2

这也是js中消除异步的方法之一——将异步任务放到特定的执行环境中进行。
虽然相比写async/await并没有提升多少开发效率,但是考虑可以结合ts的装饰器和类,将实现特定功能的类的异步方法转换成同步,并且使其在特定的执行容器中运行,则可以达到不用写async/await或promise.then()的目的。
端到端测试框架cypress可能使用的也是这样的方案。
但基于这种方案进行异步转同步也有很大的限制,会导致无法很好地和常规js同步代码兼容(必须要在执行器中运行)。