Promise.all (). Then () вирішити?


95

Використання 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
});

Але це не здається правильним способом зробити це ... Який правильний підхід до цього?

Відповіді:


142

Але це не здається правильним способом зробити це ..

Це дійсно правильний спосіб зробити це (або , по крайней мере , на правильний спосіб зробити це). Це ключовий аспект обіцянок, вони є конвеєром, і дані можуть масажуватися різними обробниками конвеєру.

Приклад:

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,

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
bhaRAT

1

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

Тільки будьте обережні та переконайтеся, що усуваєте помилки .catch(). Promise.all()відхиляє, як тільки одне із обіцянок у масиві відхиляє .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.