Использование Promise внутри цикла - PullRequest
0 голосов
/ 05 октября 2018

Я хочу понять, как работает этот код.Некоторое время я работал с обещанием, но мне интересно, что здесь происходит.

for(let i=0 ; i< 3 ;i++){
   new Promise((resolve,reject)=>{
   console.log("i = "+i)
   resolve(i)
  })
  .then(r=>{
   console.log("promise 1  of "+r)
   return new Promise((res,rej)=>res(r))
  })
  .then(r=>{
    console.log("promise 2  of "+r)
    return new Promise((res,rej)=>res(r))
  })
}

console.log("finish")

Вывод

i = 0 
i = 1 
i = 2 
finish 
promise 1  of 0 
promise 1  of 1 
promise 1  of 2 
promise 2  of 0 
promise 2  of 1 
promise 2  of 2

Почему отображается финиш до того, как другие обещания осталисьвыполнить.

Заранее спасибо

1 Ответ

0 голосов
/ 05 октября 2018

Почему отображается финиш перед тем, как остальные обещания остаются для выполнения.

Поскольку в этом коде ничего не говорит о том, что console.log ожидает выполнения обещаний перед выполнением.Если вы хотите это сделать, соберите их в массив, а затем используйте:

Promise.all(theArray)
    .then(() => {
        console.log("finish");
    });

..., чтобы сказать, что они должны ждать их всех.

Помните, что обработчики then всегда вызывается асинхронно.Таким образом, ваш код создает три цепочки обещаний, затем выводит console.log в конце, а затем получает асинхронные обратные вызовы для обработчиков then - так что эти результаты отображаются позже.


Примечание:Код в вашем вопросе может быть написан более просто так:

for(let i = 0; i < 3; i++) {
    console.log("i = " + i);
    Promise.resolve(i)
    .then(r => {
        console.log("promise 1  of " + r);
        return r;
    })
    .then(r => {
        console.log("promise 2  of " + r);
        return r;
    });
}

console.log("finish");

Почему:

  • Функция исполнителя обещания (функция, которую вы передаетеконструктор) выполняется синхронно, поэтому нет никакой разницы между строкой console.log("i = " + i); в качестве первой строки функции-исполнителя или чуть выше строки, в которой вы создаете обещание.
  • Promise.resolve создает разрешенноеобещание с указанным вами значением.
  • then всегда создает новое обещание.Когда вы возвращаете значение не обещания из обработчика then, это значение является значением разрешения обещания, возвращаемого then.Если вы вернете обещание, то созданное обещание then будет «подчинено» обещанию, которое вы вернете (ожидает его разрешения или отклонения, а затем делает то же самое).

В комментарии вы задали очень умный вопрос:

Если «затем» вызывается асинхронно, то порядок вывода этих обещаний может быть не предсказан, верно?

Незначительный момент: then не вызывается асинхронно, его обработчик (функция, которую вы передаете его) вызывается асинхронно.

В общем случае, да, верно, вы можете 'Предсказать порядок независимых обещаний (которые не связаны друг с другом).Вы можете предсказать обещания, что связаны вместе (более ранние в цепочке обрабатываются раньше, чем более поздние).В вашем коде у вас есть три независимых цепочки (одна для i = 0, одна для i = 1 и другая для i = 2);к каждой цепочке прикреплены два обработчика («1 из» и «2 из»).Итак, вы знаете, что «1 из» в цепочке «i = 0» произойдет раньше, чем «2 из» в той же цепочке, но в общем случае вы не знаете, будет ли i = 0 единица первым или i = 2один или что-то еще.

Но , в данном конкретном случае порядок можно предсказать (по крайней мере, в браузерах, а также в Node.js), поскольку начальныйОбещание в каждой цепочке начинается предварительно разрешенным, что означает, что вызов его обработчика then помещается в очередь для микрозадач сразу после вызова then.Очередь для микрозадачи запускается в конце каждой задачи (она же называется «макрозадача»).Таким образом, задача, выполняющая ваш основной код, немедленно ставит обратный вызов в очередь на обработчик «1 из» каждой цепочки.Когда этот обработчик запускается, он ставит в очередь микрозадачу для вызова обработчика «2 of».Таким образом, поскольку обещания начинают решаться, мы знаем, что получим результат, который вы получите.Но в общем случае вы правы, вы не можете предсказать между цепями.

¹ Это веб-термин для этого;спецификация JS называет это очередью PromiseJobs.Подробнее о "микрозадачах" и задачах / макрозадачах в этот ответ .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...