Возвращать новое обещание в функции по сравнению с использованием нового обещания непосредственно в асинхронном/ожидающем режиме?

#javascript #asynchronous #async-await #promise #es6-promise

Вопрос:

Когда я создаю 3 разных обещания, используя эту функцию:

 const setTimer = (num) => {
  return new Promise((res, rej) => {
    setTimeout(() => {
      res(num)
    }, 2000);
  })
} 
 

а затем запустите их внутри функции async/await:

 const func = async () => {
  const first = await setTimer(1)
  console.log(first);
  const second = await setTimer(2)
  console.log(second);
  const third = await setTimer(3)
  console.log(third);
}

func()
 

Они работают синхронно (один за другим), как и ожидалось.

Затем я создаю 3 разных обещания, используя новое обещание напрямую:

 const setTimer1 = new Promise((res, rej) => {
  setTimeout(() => {
    res(1)
  }, 2000);
})

const setTimer2 = new Promise((res, rej) => {
  setTimeout(() => {
    res(2)
  }, 2000);
})

const setTimer3 = new Promise((res, rej) => {
  setTimeout(() => {
    res(3)
  }, 2000);
})
 

А затем снова запустите эти 3 обещания в функции async/await:

 const func1 = async () => {
  const first = await setTimer1
  console.log(first);
  const second = await setTimer2
  console.log(second);
  const third = await setTimer3
  console.log(third);
}

func1()
 

Теперь они работают асинхронно (параллельно). Пожалуйста, помогите объяснить, почему. Я действительно долго искал, но так и не нашел ответа.

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

1. «Теперь они выполняются асинхронно (параллельно)» — нет. они выполняются последовательно; один за другим. Разница в обоих примерах кода заключается в том, что первый создает обещание внутри функции.

2. Обещания «начинаются» при создании экземпляра, а не при первом ожидании. Ваш первый фрагмент создает экземпляр обещания только после завершения предыдущего. Ваш второй фрагмент создает их все, а затем ожидает их.

3. setTimer() создает Promise при вызове. const setTimerX = new Promise() создает обещание немедленно.

4. Как говорили другие, Обещания начинаются при создании, поэтому в вашем случае они заканчиваются одновременно (хотя и последовательно). Попробуйте установить один на 2000, другой на 3000 и последний на 4000 — вы увидите разницу 🙂

5. @OldGeezer где? В setTimeout() или в » новом обещании ()»? Потому что оба этих возвращаемых значения отклоняются и ничего не делают.

Ответ №1:

Проще всего понять разницу, сравнив следующие примеры:

 (async () => {
    const p1 = new Promise(resolve => setTimeout(resolve, 2000));
    const p2 = new Promise(resolve => setTimeout(resolve, 2000));
    const p3 = new Promise(resolve => setTimeout(resolve, 2000));

    await p1;
    console.log(1); // 2 seconds later
    await p2;
    console.log(2); // 0 seconds later
    await p3;
    console.log(3); // 0 seconds later
})();
 

Все Обещания создаются сразу одно за другим, поэтому в то время, когда первое из них готово, все они готовы. Вот почему вы получите 1 , 2 и 3 в вашей консоли одновременно.

Но теперь рассмотрим этот пример:

 (async () => {
    await new Promise(resolve => setTimeout(resolve, 2000));
    console.log(1); // 2 seconds later
    await new Promise(resolve => setTimeout(resolve, 2000));
    console.log(2); // 2 seconds later
    await new Promise(resolve => setTimeout(resolve, 2000));
    console.log(3); // 2 seconds later
})();
 

На этот раз второе обещание будет выполнено после того, как первое будет выполнено, то есть через 2 секунды. То же самое относится и к третьему, ожидающему второго. И вот почему вы получите 1 через 2 секунды, 2 еще через 2 секунды и 3 еще через 2 секунды.

Чтобы понять почему, достаточно знать, что Обещание старается быть как можно более быстрым. Он начинает свою работу, как только он создан. И это хорошо!

Ответ №2:

Ваши последние три объявления не являются функциями. Они назначают каждому обещание, которое выполняется в момент создания каждого из них. Таким образом, они должны быть закодированы так же, как и ваш первый, где обещание создается только при вызове функции:

 const setTimer1 = () => new Promise((res, rej) => {
  setTimeout(() => {
    res(1)
  }, 2000);
})

const setTimer2 = () => new Promise((res, rej) => {
  setTimeout(() => {
    res(2)
  }, 2000);
})

const setTimer3 = () => new Promise((res, rej) => {
  setTimeout(() => {
    res(3)
  }, 2000);
})
 

Затем вам нужно вызвать каждую функцию:

 const func1 = async () => {
  const first = await setTimer1();
  console.log(first);
  const second = await setTimer2();
  console.log(second);
  const third = await setTimer3();
  console.log(third);
}

func1()
 

Необходимые изменения очень незначительны, добавлено всего несколько символов. Сравните с вашим кодом, чтобы увидеть различия.