简体   繁体   中英

Proper way to Abort (stop) running async/await function?

There has been other topics on SE, but most of them are dated 5 years ago. What is the current, up-to-date approach to cancel await call in JS? ie

async myFunc(){
    let response = await oneHourLastingFunction();
    myProcessData(response);
}

at specific moment application decides it no longer want to wait that oneHourLastingFunction , but it is stuck in "await". How to cancel that? Any standard ways of cancelation-tokens/ abortControllers for promises?

Canceling an asynchronous procedure is still not a trivial task, especially when you need deep cancellation and flow control. There is no native solution at the moment. All you can natively:

  • pass AbortController instance to each nested async function you want to make cancellable
  • subscribe all internal micro-tasks (requests, timers, etc) to the signal
  • optionally unsubscribe completed micro-tasks from the signal
  • call abort method of the controller to cancel all subscribed micro-tasks

This is quite verbose and a tricky solution with potential memory leaks.

I can just suggest my own solution to this challenge- c-promise2 , which provides cancelable promises and a cancelable alternative for ECMA asynchronous functions - generators.

Here is an basic example ( Live Demo ):

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();

Deeply cancellable solution (all functions are cancellable) ( Live Demo ):

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM