#javascript #node.js #asynchronous #design-patterns #callstack
Вопрос:
TLDR: должен ли я использовать async
и await
использовать сложный стек вызовов, если большинство функций на самом деле не async
являются таковыми ? Существуют ли альтернативные шаблоны программирования?
Контекст
Этот вопрос, вероятно, больше касается шаблонов проектирования и общей архитектуры программного обеспечения, чем конкретной проблемы синтаксиса. Я пишу алгоритм в node.js это довольно сложно. Поток программы включает в себя начальный асинхронный вызов для извлечения некоторых данных, а затем переходит к серии синхронных шагов вычисления на основе данных. Шаги вычисления являются итеративными, и по мере их выполнения они генерируют результаты. Но иногда, если при расчетах выполняются определенные условия, потребуется получить дополнительные данные. Вот упрощенная версия в виде диаграммы:
calcStep
Цикл выполняется тысячи раз синхронно, подталкивая к результатам. Но иногда он возвращается getData
, и программе приходится ждать поступления дополнительных данных, прежде чем снова переходить к calcStep
циклу.
В коде
Упрощенная версия вышесказанного может выглядеть так в коде JS:
let data;
async function init() {
data = await getData();
processData();
calcStep1();
}
function calcStep1() {
// do some calculations
calcStep2();
}
function calcStep2() {
// do more calculations
calcStep3();
}
function calcStep3() {
// do more calculations
pushToResults();
if (some_condition) {
getData(); // <------ question is here
}
if (stop_condition) {
finish();
} else {
calcStep1();
}
}
Где pushToResults
и finish
также являются простыми синхронными функциями. Я пишу calcStep
, что функции здесь разделены, потому что в реальном коде они на самом деле являются методами классов из классов, определенных на основе разделения проблем.
Проблема
Очевидная проблема возникает, если some_condition
выполняется, и мне нужно ждать, чтобы получить больше данных, прежде чем продолжить calcStep
цикл, я должен использовать await
ключевое слово перед вызовом getData
в calcStep3
, Что означает, что calcStep3
должен быть вызван async
, и мы должны await
что также В calcStep2
, и всю дорогу вверх по цепочке, даже синхронные функции должны быть обозначены async
и await
Эд.
В этом упрощенном примере было бы не так обидно это делать. Но на самом деле мой алгоритм намного сложнее, с гораздо более глубоким стеком вызовов, включающим множество методов классов, итераций и т. Д. Есть ли лучший способ управления await
функциями ing в сценариях такого типа? Другие инструменты, которые я могу использовать, такие как генераторы или излучатели событий? Я открыт для простых решений или смены парадигмы.
Ответ №1:
Если вы не хотите создавать функцию async
и распространять ее по цепочке, используйте .then()
. Вам нужно будет продублировать следующий код внутри .then()
; вы можете упростить это, поместив его в собственную функцию.
function maybeRepeat() {
if (stop_condition) {
finish();
} else {
calcStep1();
}
}
function calcStep3() {
// do more calculations
pushToResults();
if (some_condition) {
getData().then(maybeRepeat);
} else {
maybeRepeat()
}
}