Разрыв выполнения стека асинхронных вызовов

Я читаю «Красноречивый 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));

Но это работает, как и ожидалось. Сумму печатает правильно. Так я неправильно понял книгу или что-то не так с моим примером?

а) ваша функция delay реализует обещание setTimeout неправильно б) ваша функция delay не возвращает обещание, которое разрешается в аргумент n

Bergi 16.05.2022 03:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
24
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в исходном коде заключается в том, что здесь:

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 для имитации обещания. Дурак я! Спасибо за это!

dragonfly02 16.05.2022 04:28

Другие вопросы по теме