Правильный способ прервать (остановить) выполнение функции async/await?

0

Вопрос

На SE были и другие темы, но большинство из них датировано 5 годами назад. Каков текущий, актуальный подход к отмене вызова ожидания в JS? т.е.

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

в определенный момент приложение решает, что больше не хочет ждать, что oneHourLastingFunction, но он застрял в "ожидании". Как это отменить? Какие-либо стандартные способы отмены-токены/контроллеры прерывания для обещаний?

1

Лучший ответ

1

Отмена асинхронной процедуры по-прежнему не является тривиальной задачей, особенно когда вам нужна глубокая отмена и управление потоком. На данный момент нет собственного решения. Все, что вы можете сделать изначально:

  • передайте экземпляр 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();

Полностью отменяемое решение (все функции отменяются) (Демонстрация в реальном времени):

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);
2021-11-25 16:48:29

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................