Forbidden
@Forbidden
CEO, CTO @ a-parser.com

Как снаружи прервать выполнение асинхронной функции?

Всем привет, рассматриваем вопрос о миграции одного проекта с Perl/Coro на nodejs(8.x)/async/await, столкнулись со следующей проблемой:

const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));

let asyncFn = async () => {
    while(1) {
        await snooze(1000);
        console.log(Date.now());
    }
}

let asyncPromise = asyncFn();

setTimeout(() => {
    console.log("try destroy");
    asyncPromise = null;
}, 1500);


Каким образом можно прервать выполнение асинхронной функции? Вариант с внешним флагом не рассматривается по следующей причине:
  • Необходимость прервать выполнение может попасть на долгий sleep и долгую сетевую операцию
  • Постоянная проверка флага перед каждым await убивает всю элегантность решения


В других языках, в частности в Perl/Coro корутину всегда можно прервать или кинуть в нее исключение.
Честно говоря после гугления надежд мало, но все же, есть гуру кто решил эту проблему?
  • Вопрос задан
  • 4301 просмотр
Пригласить эксперта
Ответы на вопрос 4
Negwereth
@Negwereth
lvivcss.com.ua
throw.
Вызовы при этом надо в try...catch заворачивать.
Ответ написан
Forbidden
@Forbidden Автор вопроса
CEO, CTO @ a-parser.com
Для всех сочувствующих - рекомендую не читать предыдущие комменты, там вы получите батхерд который никак не относится к теме топика

Вот большая дискуссия о включение cancelation в стандарт https://github.com/tc39/ecmascript-asyncawait/issues/27
TL;DR в конце концов там никчему и не пришли

Еще интересные ссылки:
https://github.com/getify/asynquence - библиотека одного из активных комментаторов в том топике, реализует поддержку отмены
https://github.com/JeffreyZhao/windjs.org-cn/blob/... - китайцы реализуют отмену через canelation token(привет C#) в 2012 году

И скорее всего самое главное:
https://github.com/tc39/proposal-cancellation - свежее предложение в стандарт и готовая реализация https://github.com/rbuckton/prex
Ответ написан
SynCap
@SynCap
Делаю интернет с 1998 года
Если флаги не вариант, тогда только запихнуть асинхронную задачу в отдельный процесс - его при желании можно прибить. Для отдельного процесса, можно легко организовать `await`.
Читать тут
Ничего не мешает сделать отдельные самостоятельные модули под асинхронные процессы.
Таким макаром можно организовать аналог многопоточности с балансировкой, контролем приоритетов. чифирем и папиросами.

* npmjs.com/package/invoke-parallel
* npmjs.com/package/runnablepool
* npmjs.com/package/child-pool

Есть еще workers и cluster

И не надо забывать, что вся асинхронность Ноды - на событиях (Event Loop)
Ответ написан
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Сделай на Promise();
Тогда тебе наружу надо просто выкинуть Промис и в другом потоке вызывать Promise.resolve(); и не нужно будет ждать пока первый поток вызовет.

Придется немного пересмотреть логику но выйдет примерно так:
1. Ты ждешь от промиза некоего результата или ошибки
2. В другом потоке произошло нечто, что требует закончить действие. Возвращаешь из другого потока реджект с массивом, в первом параметре код ошибки, во втором сообщение.

Работаешь как будто получил эти данные из основного промиза, дважды он не резолвнется и не реджекнется.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы