Promise.all (). Then () разрешить?


96

Используя Node 4.x. Когда у вас есть вопрос, Promise.all(promises).then()как правильно разрешить данные и передать их следующему .then()?

Я хочу сделать что-то вроде этого:

Promise.all(promises).then(function(data){
  // Do something with the data here
}).then(function(data){
  // Do more stuff here
});

Но я не уверен, как получить данные на 2-й .then(). Я не могу использовать resolve(...)в первом .then(). Я понял, что могу это сделать:

return Promise.all(promises).then(function(data){
  // Do something with the data here
  return data;
}).then(function(data){
  // Do more stuff here
});

Но это не похоже на правильный способ сделать это ... Как правильный подход к этому?

Ответы:


143

Но это не похоже на правильный способ сделать это ...

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

Пример:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("First handler", data);
    return data.map(entry => entry * 10);
  })
  .then(data => {
    console.log("Second handler", data);
  });

( catchобработчик опущен для краткости. В рабочем коде всегда либо распространяйте обещание, либо обрабатывайте отклонение.)

Результат, который мы видим из этого:

Первый обработчик [1,2]
Второй обработчик [10,20]

... потому что первый обработчик получает разрешение двух обещаний ( 1и 2) в виде массива, а затем создает новый массив с каждым из них, умноженным на 10, и возвращает его. Второй обработчик получает то, что вернул первый обработчик.

Если дополнительная работа, которую вы выполняете, синхронна, вы также можете поместить ее в первый обработчик:

Пример:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("Initial data", data);
    data = data.map(entry => entry * 10);
    console.log("Updated data", data);
    return data;
  });

... но если он асинхронный, вы не захотите этого делать, так как в конечном итоге оно становится вложенным, и вложение может быстро выйти из-под контроля.


1
Интересно. Спасибо. Значит, невозможно rejectзначение после начальной Promiseфункции? Или сообщение об ошибке в любом месте цепочки приведет вас к .catch()? Если это так, то в чем вообще смысл reject? Почему бы просто не выдать ошибку? Еще раз спасибо,
Джейк Уилсон

6
@JakeWilson: Это разные вопросы. Но вы путаете две разные вещи: создание и выполнение обещания и обработку обещания. Когда вы создаете и выполняете обещание, вы используете resolveи reject. Когда вы обрабатываете , если ваша обработка терпит неудачу, вы действительно генерируете исключение, чтобы запустить путь отказа. И да, вы также можете генерировать исключение из исходного Promiseобратного вызова (вместо использования reject), но не все сбои являются исключениями.
TJ Crowder

2

Ваш return dataподход правильный, это пример цепочки обещаний . Если вы вернете обещание из своего .then()обратного вызова, JavaScript разрешит это обещание и передаст данные следующему then()обратному вызову.

Просто будьте осторожны и убедитесь, что вы обрабатываете ошибки с помощью .catch(). Promise.all()отклоняет, как только одно из обещаний в массиве отклоняется .


1

Сегодня NodeJS поддерживает новый async/awaitсинтаксис. Это простой синтаксис, который значительно облегчает жизнь

async function process(promises) { // must be an async function
    let x = await Promise.all(promises);  // now x will be an array
    x = x.map( tmp => tmp * 10);              // proccessing the data.
}

const promises = [
   new Promise(resolve => setTimeout(resolve, 0, 1)),
   new Promise(resolve => setTimeout(resolve, 0, 2))
];

process(promises)

Учить больше:


1
как я могу передать параметры каждому отдельному обещанию из процесса? @ Aminadav Glickshtein
bhaRATh
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.