Я читаю «Красноречивый JavaScript», и в конце главы «Асинхронный» есть раздел о разрыве выполнения в асинхронных операциях, и он показывает пример. Приведенный ниже пример кода из книги не запускается, поскольку он использует какой-то выдуманный сценарий.
function anyStorage(nest, source, name) {
if (source == nest.name) return storage(nest, name); else return routeRequest(nest, source, "storage", name);
}
async function chicks(nest, year) {
let list = "";
await Promise.all(network(nest).map(async name => {
list += `${name}: ${
await anyStorage(nest, name, `chicks in ${year}`)
}\n`; }));
return list;
}
В нем говорится, что проблема с этим кодом, как я понимаю, заключается в каждом асинхронном вызове, например. anyStorage фактически объединит пустой list и не сможет увидеть мутацию из других асинхронных вызовов.
Я попытался воспроизвести эту проблему, как показано ниже:
function delay(n) {
return Promise.resolve(setTimeout(()=>{}, n*1000));
}
async function asyncSum(a) {
let sum = 0;
await Promise.all(a.map(async i => sum += await delay(i)));
return sum;
}
asyncSum([1,2,3,4]).then(value => console.info(value));
Но это работает, как и ожидалось. Сумму печатает правильно. Так я неправильно понял книгу или что-то не так с моим примером?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Проблема в исходном коде заключается в том, что здесь:
list += `${name}: ${ await ...
list += похоже на list = list +, но второй список:
list = list +
^^^^
относится к listв тот момент - до завершения любого из асинхронных вызовов. В конце концов один из них завершится и будет назначен list. Но как только следующий результат разрешится, поскольку list он относится к исходному, а не к недавно обновленному, предыдущие результаты будут потеряны.
Вот демо:
const getMultipliedNum = num => Promise.resolve(num * 3);
(async() => {
let list = "";
await Promise.all([1, 2, 3].map(async num => {
list += `${num}: ${ await getMultipliedNum(num)}\n`;
}));
console.info(list);
})();В вашем примере та же проблема, хотя функция delay не работает — результат равен 4, что является результатом только последнего вызова setTimeout (поскольку setTimeout возвращает идентификатор тайм-аута). Исправление для демонстрации проблемы:
function delay(n) {
return Promise.resolve(n);
}
async function asyncSum(a) {
let sum = 0;
await Promise.all(a.map(async i => sum += await delay(i)));
return sum;
}
asyncSum([1,2,3,4]).then(value => console.info(value));Результат — 4, а не 10 — это демонстрирует, что sum += await somethingElse внутри параллельного цикла не работает.
Другой способ взглянуть на это:
sum += await somethingElse
это как делать
const currentValueOfSum = sum;
sum = currentValueOfSum + await somethingElse;
О боже, не знаю, почему я использовал setTimeOut для имитации обещания. Дурак я! Спасибо за это!
а) ваша функция
delayреализует обещаниеsetTimeoutнеправильно б) ваша функцияdelayне возвращает обещание, которое разрешается в аргументn