Первое обещание внутри Promise.all() выполняется неправильно

#javascript #asynchronous #async-await #promise

Вопрос:

wait функция используется в качестве функции сна, fn функция принимает массив (элементы), регистрирует каждый элемент и отключается на секунду, прежде чем регистрировать следующий элемент.

 const wait = async(time) => {
  return new Promise((resolve) => setTimeout(resolve, time))
}

const fn = async(items) => {
  for (item of items) {
    await wait(1000)
    console.log(item)
  }
}

const exeAll = async() => {
  Promise.all([
    fn(['A1', 'A2']),
    fn(['B1', 'B2']),
  ])
}

exeAll() 

Проблема заключается в результате, предоставляемом exeAll функцией, которая выводит:

 B1
A2
B2
B2
 

Но я думаю, что на нем должно быть напечатано что-то вроде:

 A1
B1
A2
B2
 

A1 вообще не отображается при выполнении приведенного выше кода. Кто-нибудь может объяснить, почему ?

Комментарии:

1. Если вы await звоните fn() по Promise.all() вызову, он работает именно так, как вы ожидаете.

2. и B2 всегда регистрируется дважды в конце.

3. Не нужно exeAll быть асинхронным.

4. Я не хочу, чтобы await они, ожидая их, заставляли их выполнять все по порядку. что бы напечатать: A1 A2 B1 B2

5. Я удалил async ключевое слово из функции exeAll, и ничего не изменилось, проблема всегда есть. A1 не печатается и B2 печатается дважды.

Ответ №1:

for (item of items) { создаст неявную глобальную переменную item , т. е. несколько вызовов fn будут мешать друг другу, перезаписывая item . Правильно объявите переменную, и она будет работать так, как ожидалось:

 const wait = async(time) => {
  return new Promise((resolve) => setTimeout(resolve, time))
}

const fn = async(items) => {
  for (let item of items) {
  //   ^^^^
    await wait(1000)
    console.log(item)
  }
}

const exeAll = async() => {
  Promise.all([
    fn(['A1', 'A2']),
    fn(['B1', 'B2']),
  ])
}

exeAll() 

Мы можем добавить дополнительные записи fn , чтобы узнать, что происходит, когда в вашем случае:

 const wait = async(time) => {
  return new Promise((resolve) => setTimeout(resolve, time))
}

let counter = 0;
const fn = async(items) => {
  const c = counter  ;
  console.log(`enter fn call #${c}`);
  for (item of items) {
    console.log(`fn call #${c} sets item <-`, item);
    await wait(1000)
     console.log(`fn call #${c} reads item ->`, item);
    console.log(item)
  }
}

const exeAll = async() => {
  Promise.all([
    fn(['A1', 'A2']),
    fn(['B1', 'B2']),
  ])
}

exeAll() 

Строгий режим ( "use strict"; ) поймал бы эту ошибку, потому что назначение необъявленной переменной приводит к ошибке.

Комментарии:

1. Строгий режим ( "use strict"; ) поймал бы это, потому что присвоение необъявленным переменным приводит к ошибке 😉

2. Точно. «строгий режим» — это первое, что пришло мне в голову, когда я впервые увидел ваш ответ.