Promise.all (). Potem () rozwiązać?

96

Korzystanie z Node 4.x. Kiedy masz Promise.all(promises).then()właściwy sposób rozwiązania danych i przekazania ich następnemu .then()?

Chcę zrobić coś takiego:

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

Ale nie jestem pewien, jak uzyskać dane do drugiego .then(). Nie mogę użyć resolve(...)w pierwszym .then(). Pomyślałem, że mogę to zrobić:

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

Ale to nie wydaje się być właściwym sposobem na zrobienie tego ... Jakie jest właściwe podejście do tego?

Jake Wilson
źródło

Odpowiedzi:

143

Ale to nie wydaje się być właściwym sposobem na zrobienie tego.

To jest rzeczywiście właściwym sposobem, aby to zrobić (lub co najmniej na właściwy sposób to zrobić). Jest to kluczowy aspekt obietnic, są one potokiem, a dane mogą być masowane przez różne moduły obsługi w potoku.

Przykład:

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);
  });

( catchmoduł obsługi pominięty ze względu na zwięzłość. W kodzie produkcyjnym zawsze albo propaguj obietnicę, albo obsługuj odrzucenie).

Wynik, który widzimy z tego to:

Pierwsza osoba zajmująca się obsługą [1,2]
Drugi przewodnik [10,20]

... ponieważ pierwszy program obsługi otrzymuje rozdzielczość dwóch obietnic ( 1i 2) jako tablicę, a następnie tworzy nową tablicę z każdą z nich pomnożoną przez 10 i zwraca ją. Drugi program obsługi pobiera to, co zwrócił pierwszy program obsługi.

Jeśli dodatkowa praca, którą wykonujesz, jest synchroniczna, możesz również umieścić ją w pierwszym module obsługi:

Przykład:

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;
  });

... ale jeśli jest asynchroniczny, nie chcesz tego robić, ponieważ kończy się zagnieżdżaniem, a zagnieżdżanie może szybko wymknąć się spod kontroli.

TJ Crowder
źródło
1
Ciekawy. Dziękuję Ci. Czy więc nie jest możliwe rejectuzyskanie wartości po Promisefunkcji początkowej ? A może wyrzucenie błędu gdziekolwiek w łańcuchu przeniesie Cię do .catch()? Jeśli tak jest, jaki jest sens tego rejectw pierwszej kolejności? Dlaczego po prostu nie wyrzucić błędu? Jeszcze raz dziękuję
Jake Wilson,
6
@JakeWilson: To są różne pytania. Ale mylisz dwie oddzielne rzeczy: tworzenie i wypełnianie obietnicy oraz radzenie sobie z obietnicą. Kiedy tworzysz i realizujesz obietnicę, używasz resolvei reject. Podczas obsługi , jeśli przetwarzanie nie powiedzie się, faktycznie zgłaszasz wyjątek, aby wyzwolić ścieżkę niepowodzenia. I tak, możesz również zgłosić wyjątek od pierwotnego Promisewywołania zwrotnego (zamiast używać reject), ale nie wszystkie awarie są wyjątkami.
TJ Crowder
1

Obecnie NodeJS obsługuje nową async/awaitskładnię. Jest to prosta składnia i znacznie ułatwia życie

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)

Ucz się więcej:

Aminadav Glickshtein
źródło
1
jak mogę przekazać parametry do każdej indywidualnej obietnicy z procesu? @ Aminadav Glickshtein
bhaRATh