中止(停止)运行异步/等待函数的正确方法?

T.T*_*dua 5 javascript asynchronous promise cancellation

SE 上还有其他主题,但大多数都是 5 年前的。当前取消 JS 中的等待调用的最新方法是什么?IE

async myFunc(){
    let response = await oneHourLastingFunction();
    myProcessData(response);
}
Run Code Online (Sandbox Code Playgroud)

在特定时刻,应用程序决定不再等待oneHourLastingFunction,但它陷入“等待”状态。怎么取消呢?承诺的取消令牌/中止控制器有任何标准方法吗?

Dmi*_*voy 6

取消异步过程仍然不是一项简单的任务,特别是当您需要深度取消和流程控制时。目前没有本地解决方案。您可以在本地执行的所有操作:

  • 将 AbortController 实例传递给您想要取消的每个嵌套异步函数
  • 将所有内部微任务(请求、计时器等)订阅到信号
  • 可选择取消订阅信号中已完成的微任务
  • 调用abort控制器的方法取消所有订阅的微任务

这是一个非常冗长且棘手的解决方案,并且存在潜在的内存泄漏。

我可以针对这个挑战提出我自己的解决方案 - c-promise2,它提供了可取消的承诺和 ECMA 异步函数的可取消替代方案 - 生成器。

这是一个基本示例(现场演示):

import { CPromise } from "c-promise2";

// deeply cancelable generator-based asynchronous function
const oneHourLastingFunction = CPromise.promisify(function* () {
  // optionally just for logging
  this.onCancel(() =>
    console.log("oneHourLastingFunction::Cancel signal received")
  );
  yield CPromise.delay(5000); // this task will be cancelled on external timeout
  return "myData";
});

async function nativeAsyncFn() {
  await CPromise.delay(5000);
}

async function myFunc() {
  let response;
  try {
    response = await oneHourLastingFunction().timeout(2000);
  } catch (err) {
    if (!CPromise.isCanceledError(err)) throw err;
    console.warn("oneHourLastingFunction::timeout", err.code); // 'E_REASON_TIMEOUT'
  }
  await nativeAsyncFn(response);
}

const nativePromise = myFunc();
Run Code Online (Sandbox Code Playgroud)

深度可取消方案(所有功能均可取消)(现场演示):

import { CPromise } from "c-promise2";

// deeply cancelable generator-based asynchronous function
const oneHourLastingFunction = CPromise.promisify(function* () {
  yield CPromise.delay(5000);
  return "myData";
});

const otherAsyncFn = CPromise.promisify(function* () {
  yield CPromise.delay(5000);
});

const myFunc = CPromise.promisify(function* () {
  let response;
  try {
    response = yield oneHourLastingFunction().timeout(2000);
  } catch (err) {
    if (err.code !== "E_REASON_TIMEOUT") throw err;
    console.log("oneHourLastingFunction::timeout");
  }
  yield otherAsyncFn(response);
});

const cancellablePromise = myFunc().then(
  (result) => console.log(`Done: ${result}`),
  (err) => console.warn(`Failed: ${err}`)
);

setTimeout(() => {
  console.log("send external cancel signal");
  cancellablePromise.cancel();
}, 4000);
Run Code Online (Sandbox Code Playgroud)