Obsługa błędów w Promise.all

266

Mam szereg obietnic, które realizuję Promise.all(arrayOfPromises);

Kontynuuję, aby kontynuować łańcuch obietnic. Wygląda mniej więcej tak

existingPromiseChain = existingPromiseChain.then(function() {
  var arrayOfPromises = state.routes.map(function(route){
    return route.handler.promiseHandler();
  });
  return Promise.all(arrayOfPromises)
});

existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
  // do stuff with my array of resolved promises, eventually ending with a res.send();
});

Chcę dodać instrukcję catch, aby obsłużyć indywidualną obietnicę na wypadek błędu, ale gdy spróbuję, Promise.allzwraca pierwszy znaleziony błąd (ignoruje resztę), a następnie nie mogę uzyskać danych z pozostałych obietnic w tablica (to nie błąd).

Próbowałem zrobić coś takiego ...

existingPromiseChain = existingPromiseChain.then(function() {
      var arrayOfPromises = state.routes.map(function(route){
        return route.handler.promiseHandler()
          .then(function(data) {
             return data;
          })
          .catch(function(err) {
             return err
          });
      });
      return Promise.all(arrayOfPromises)
    });

existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
      // do stuff with my array of resolved promises, eventually ending with a res.send();
});

Ale to nie rozwiązuje problemu.

Dzięki!

-

Edytować:

Poniższe odpowiedzi były całkowicie prawdziwe, kod łamał się z innych powodów. Jeśli ktoś jest zainteresowany, oto rozwiązanie, w którym znalazłem ...

Łańcuch Node Express Server

serverSidePromiseChain
    .then(function(AppRouter) {
        var arrayOfPromises = state.routes.map(function(route) {
            return route.async();
        });
        Promise.all(arrayOfPromises)
            .catch(function(err) {
                // log that I have an error, return the entire array;
                console.log('A promise failed to resolve', err);
                return arrayOfPromises;
            })
            .then(function(arrayOfPromises) {
                // full array of resolved promises;
            })
    };

Wywołanie API (wywołanie route.async)

return async()
    .then(function(result) {
        // dispatch a success
        return result;
    })
    .catch(function(err) {
        // dispatch a failure and throw error
        throw err;
    });

Uruchamianie systemu .catchza Promise.allzanim .thenWydaje się, że służył łapania błędów od pierwotnych obietnic, ale potem wraca całą tablicę do następnego.then

Dzięki!

Jon
źródło
2
Twoja próba wydaje się, że powinna zadziałać… może gdzieś później jest jakiś problem?
Ry-
.then(function(data) { return data; })można całkowicie pominąć
Bergi
Jedynym powodem, dla którego powyższe nie powinno być rozwiązane, jest to, że nie wyświetlasz nam całego kodu w thenlub catchhandlerach i jest w nim błąd. Nawiasem mówiąc, czy ten węzeł?
1
Nie masz ostatecznego połowu w „istniejącym łańcuchu”, więc mogą wystąpić błędy, których nie widzisz, które mogą wyjaśniać, dlaczego „nie rozwiązuje”. Spróbuj to dodać i sprawdź, jaki masz błąd.
wysięgnik
oto odpowiedź: stackoverflow.com/questions/31424561/...
Humoyun Ahmad

Odpowiedzi:

189

Promise.alljest wszystkim albo niczym. Rozpatruje się, gdy wszystkie obietnice w tablicy zostaną rozpatrzone lub odrzuć, gdy tylko jedna z nich odrzuci. Innymi słowy, albo rozwiązuje z tablicą wszystkich rozwiązanych wartości, albo odrzuca z pojedynczym błędem.

Niektóre biblioteki mają coś zwanego Promise.when, co, jak rozumiem, zamiast tego czekałoby, aż wszystkie obietnice w tablicy zostaną rozwiązane lub odrzucone, ale nie znam tego i nie ma go w ES6.

Twój kod

Zgadzam się z innymi tutaj, że Twoja poprawka powinna działać. Powinno to zostać rozwiązane za pomocą tablicy, która może zawierać mieszankę udanych wartości i obiektów błędów. Rzadko zdarza się przekazywać obiekty błędów na ścieżce sukcesu, ale zakładając, że kod ich oczekuje, nie widzę z tym problemu.

Jedynym powodem, dla którego mogę wymyślić, dlaczego „nie można rozwiązać”, jest to, że nie działa kod, którego nam nie pokazujesz, a powodem, dla którego nie widzisz żadnego komunikatu o błędzie, jest to, że ten łańcuch obietnic nie jest zakończony końcową catch (o ile i tak nam pokazujesz).

Pozwoliłem sobie na uwzględnienie „istniejącego łańcucha” z twojego przykładu i zakończenie łańcucha z haczykiem. To może nie być odpowiednie dla ciebie, ale dla osób czytających to ważne jest, aby zawsze zwracać lub kończyć łańcuchy, lub potencjalne błędy, nawet błędy w kodowaniu, zostaną ukryte (co, jak podejrzewam, miało miejsce tutaj):

Promise.all(state.routes.map(function(route) {
  return route.handler.promiseHandler().catch(function(err) {
    return err;
  });
}))
.then(function(arrayOfValuesOrErrors) {
  // handling of my array containing values and/or errors. 
})
.catch(function(err) {
  console.log(err.message); // some coding error in handling happened
});
wysięgnik
źródło
4
Ty (i powyższe komentarze) miałeś rację. Mój route.handler.promiseHandler musiał .catch () i zwrócić błąd. Musiałem także dodać końcową .catch () na końcu łańcucha. Dziękujemy za przekazanie znaczenia obsługi błędów / procedur obsługi błędów na każdym etapie łańcucha :).
Jon
2
Dowiedziałem się również, że jeśli wrzucę błąd do mojej metody .catch () dla route.handler.promiseHandler, automatycznie przejdzie on do ostatniego połowu. Jeśli zamiast tego zwrócę błąd, zrobi to, co chcę i obsłuży całą tablicę.
Jon
2
Istnieje teraz standardowa metoda Promise.allSettled()z przyzwoitym wsparciem. Zobacz referencje .
Andréa Maugars,
Tak, Promise.allnie powiedzie się, gdy pierwszy wątek zawiedzie Ale niestety wszystkie pozostałe wątki nadal działają, dopóki się nie zakończą. Nic nie jest anulowane, a nawet gorzej: Nie ma możliwości anulowania wątku Promise. Zatem cokolwiek robią (i manipulują) wątki, kontynuują, zmieniają stany i zmienne, używają procesora, ale na koniec nie zwracają wyniku. Musisz być tego świadomy, aby nie wywoływać chaosu, np. Podczas powtarzania / ponawiania połączenia.
Marc Wäckerlin
143

NOWA ODPOWIEDŹ

const results = await Promise.all(promises.map(p => p.catch(e => e)));
const validResults = results.filter(result => !(result instanceof Error));

PRZYSZŁA obietnica API

Solominh
źródło
11
Chociaż enie musi to być Error. Może to być ciąg znaków, na przykład, jeśli ktoś go zwróci Promise.reject('Service not available').
Klesun
@ArturKlesun, jak moglibyśmy następnie sklasyfikować, która z obietnic spowodowała błąd, a która nie?
Shubham Jain,
5
@ Shubham-jain z .then()i .catch(). Promise.resolve()przekazałby wartość pierwszemu, podczas gdy Promise.reject()przekazałby ją drugiemu. Można owinąć je w obiekcie np p.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e})).
Klesun
2
Dlaczego miałbyś filtrować wyniki? To nie ma sensu, jeśli robisz coś z wynikami - potrzebujesz zamówienia, aby wiedzieć, która wartość jest z jakiej obietnicy!
Ryan Taylor
21

Aby kontynuować Promise.allpętlę (nawet gdy Obietnica odrzuca), napisałem funkcję narzędziową, która jest wywoływana executeAllPromises. Ta funkcja narzędzia zwraca obiekt za pomocą resultsi errors.

Chodzi o to, że wszystkie obietnice, które przekażesz, executeAllPromiseszostaną opakowane w nową obietnicę, która zawsze będzie rozpatrywana. Nowa obietnica jest rozpatrywana za pomocą tablicy z 2 punktami. Pierwsze miejsce zawiera wartość rozstrzygającą (jeśli istnieje), a drugie miejsce utrzymuje błąd (jeśli opakowana obietnica odrzuca).

W ostatnim kroku executeAllPromiseskumuluje wszystkie wartości zapakowanych obietnic i zwraca ostateczny obiekt z tablicą dla resultsi tablicą dla errors.

Oto kod:

function executeAllPromises(promises) {
  // Wrap all Promises in a Promise that will always "resolve"
  var resolvingPromises = promises.map(function(promise) {
    return new Promise(function(resolve) {
      var payload = new Array(2);
      promise.then(function(result) {
          payload[0] = result;
        })
        .catch(function(error) {
          payload[1] = error;
        })
        .then(function() {
          /* 
           * The wrapped Promise returns an array:
           * The first position in the array holds the result (if any)
           * The second position in the array holds the error (if any)
           */
          resolve(payload);
        });
    });
  });

  var errors = [];
  var results = [];

  // Execute all wrapped Promises
  return Promise.all(resolvingPromises)
    .then(function(items) {
      items.forEach(function(payload) {
        if (payload[1]) {
          errors.push(payload[1]);
        } else {
          results.push(payload[0]);
        }
      });

      return {
        errors: errors,
        results: results
      };
    });
}

var myPromises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.reject(new Error('3')),
  Promise.resolve(4),
  Promise.reject(new Error('5'))
];

executeAllPromises(myPromises).then(function(items) {
  // Result
  var errors = items.errors.map(function(error) {
    return error.message
  }).join(',');
  var results = items.results.join(',');
  
  console.log(`Executed all ${myPromises.length} Promises:`);
  console.log(`— ${items.results.length} Promises were successful: ${results}`);
  console.log(`— ${items.errors.length} Promises failed: ${errors}`);
});

Benny Neugebauer
źródło
2
Można to zrobić prościej. Zobacz stackoverflow.com/a/36115549/918910
jib
18

ES2020 wprowadza nową metodę typu Promise: Promise.allSettled()
Promise.allSettled daje sygnał, gdy wszystkie obietnice wejściowe zostaną rozliczone, co oznacza, że ​​są one spełnione lub odrzucone. Jest to przydatne w przypadkach, gdy nie zależy ci na stanie obietnicy, chcesz tylko wiedzieć, kiedy praca jest wykonywana, niezależnie od tego, czy się powiedzie.

const promises = [
  fetch('/api-call-1'),
  fetch('/api-call-2'),
  fetch('/api-call-3'),
];
// Imagine some of these requests fail, and some succeed.

const result = await Promise.allSettled(promises);
console.log(result.map(x=>s.status));
// ['fulfilled', 'fulfilled', 'rejected']

Przeczytaj więcej w poście na blogu v8 https://v8.dev/features/promise-combinators

MosheZada
źródło
13

Jak powiedział @jib,

Promise.all jest wszystkim albo niczym.

Możesz jednak kontrolować niektóre obietnice, które „mogą” zawieść i chcielibyśmy kontynuować .then.

Na przykład.

  Promise.all([
    doMustAsyncTask1,
    doMustAsyncTask2,
    doOptionalAsyncTask
    .catch(err => {
      if( /* err non-critical */) {
        return
      }
      // if critical then fail
      throw err
    })
  ])
  .then(([ mustRes1, mustRes2, optionalRes ]) => {
    // proceed to work with results
  })
Herman
źródło
6

jeśli skorzystasz z biblioteki q https://github.com/kriskowal/q , ma ona metodę q.allSettled (), która może rozwiązać ten problem, możesz obsłużyć każdą obietnicę w zależności od jej stanu albo pełna, albo odrzucona,

existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
  return route.handler.promiseHandler();
});
return q.allSettled(arrayOfPromises)
});

existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
//so here you have all your promises the fulfilled and the rejected ones
// you can check the state of each promise
arrayResolved.forEach(function(item){
   if(item.state === 'fulfilled'){ // 'rejected' for rejected promises
     //do somthing
   } else {
     // do something else
   }
})
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Mohamed Mahmoud
źródło
Ponieważ sugerujesz użycie jakiejś biblioteki ( q), bardziej przydatne byłoby podanie przykładu użycia związanego z pytaniem. W obecnej formie odpowiedź nie wyjaśnia, w jaki sposób ta biblioteka może pomóc w rozwiązaniu problemu.
ishmaelMakitla
dodał przykład, zgodnie z sugestią
Mohamed Mahmoud,
1
Około 2018 roku należy zawsze zobaczyć, co Sindre ma do dyspozycji :-). github.com/sindresorhus/p-settle . Dzięki modułom jednofunkcyjnym Sindre nie musisz importować ogromnej biblioteki, takiej jak q, tylko na jeden bit.
DKebler
6

Korzystanie z Async oczekuje -

tutaj jedna funkcja asynchroniczna func1 zwraca wartość rozwiązaną, a func2 zgłasza błąd i zwraca wartość null w tej sytuacji, możemy sobie z tym poradzić tak, jak chcemy i odpowiednio zwrócić.

const callingFunction  = async () => {
    const manyPromises = await Promise.all([func1(), func2()]);
    console.log(manyPromises);
}


const func1 = async () => {
    return 'func1'
}

const func2 = async () => {
    try {
        let x;
        if (!x) throw "x value not present"
    } catch(err) {
       return null
    }
}

callingFunction();

Dane wyjściowe to - ['func1', null]

Nayan Patel
źródło
4

Dla osób używających ES8, które się tutaj natkną, możesz wykonać następujące czynności, używając funkcji asynchronicznych :

var arrayOfPromises = state.routes.map(async function(route){
  try {
    return await route.handler.promiseHandler();
  } catch(e) {
    // Do something to handle the error.
    // Errored promises will return whatever you return here (undefined if you don't return anything).
  }
});

var resolvedPromises = await Promise.all(arrayOfPromises);
Tyler Yasaka
źródło
3

Możemy obsłużyć odrzucenie na poziomie indywidualnych obietnic, więc gdy otrzymamy wyniki w naszej tablicy wyników, indeks tablicy, który został odrzucony, będzie undefined. Możemy poradzić sobie z tą sytuacją w razie potrzeby i wykorzystać pozostałe wyniki.

Tutaj odrzuciłem pierwszą obietnicę, więc jest ona niezdefiniowana, ale możemy wykorzystać wynik drugiej obietnicy, która ma indeks 1.

const manyPromises = Promise.all([func1(), func2()]).then(result => {
    console.log(result[0]);  // undefined
    console.log(result[1]);  // func2
});

function func1() {
    return new Promise( (res, rej) => rej('func1')).catch(err => {
        console.log('error handled', err);
    });
}

function func2() {
    return new Promise( (res, rej) => setTimeout(() => res('func2'), 500) );
}

Nayan Patel
źródło
Jak możesz zrobić podobnie, jeśli używamy asynchronizacji?
Rudresh Ajgaonkar,
Odpowiedziałem na twoje pytanie, proszę znaleźć link do odpowiedzi. stackoverflow.com/a/55216763/4079716
Nayan Patel
2

Czy rozważałeś Promise.prototype.finally()?

Wygląda na to, że został zaprojektowany tak, aby robić dokładnie to, co chcesz - wykonać funkcję, gdy wszystkie obietnice zostaną rozliczone (rozwiązane / odrzucone), niezależnie od niektórych obietnic odrzuconych.

Z dokumentacji MDN :

Ta finally()metoda może być przydatna, jeśli chcesz wykonać przetwarzanie lub czyszczenie po rozliczeniu obietnicy, niezależnie od jej wyniku.

finally()Metoda jest bardzo podobna do wywoływania .then(onFinally, onFinally)jednak istnieje kilka różnic:

Podczas tworzenia funkcji wbudowanej można ją przekazać raz, zamiast zmuszać ją do dwukrotnego zadeklarowania lub utworzenia dla niej zmiennej.

Ostatecznie wywołanie zwrotne nie otrzyma żadnego argumentu, ponieważ nie ma wiarygodnych sposobów ustalenia, czy obietnica została spełniona, czy odrzucona. Ten przypadek użycia jest właśnie wtedy, gdy nie obchodzi Cię powód odrzucenia lub wartość spełnienia, a więc nie musisz go podawać.

W przeciwieństwie do Promise.resolve(2).then(() => {}, () => {})(który zostanie rozwiązany z niezdefiniowanym), Promise.resolve(2).finally(() => {})zostanie rozwiązany z 2. Podobnie, w przeciwieństwie do Promise.reject(3).then(() => {}, () => {})(który zostanie spełniony z niezdefiniowanym), Promise.reject(3).finally(() => {})zostanie odrzucony z 3.

== Awaria ==

Jeśli Twoja wersja JavaScript nie obsługuje Promise.prototype.finally(), możesz skorzystać z tego obejścia od Jake'a Archibalda :Promise.all(promises.map(p => p.catch(() => undefined)));

Tom Auger
źródło
1
Tak, dopóki nie Promises.allSettled()zostanie faktycznie zaimplementowany (jest to udokumentowane tutaj przez MDN ), wtedy Promises.all.finally()wydaje się, że osiągnie to samo. Zaraz spróbuję ...
jamess
@jamess Dlaczego nie podasz tego komentarza jako prawidłowej odpowiedzi? Żadna z odpowiedzi nie dotyczy ES6 allSettled().
pravin
@pravin - Z tego co wiem, allSettled()nie jest nigdzie (jeszcze) zaimplementowany, więc nie chcę wyprzedzać rzeczywistości. Miałem sukces Promises.all(myPromiseArray).finally()i to pasuje do tej odpowiedzi. Gdy już allSettled()istnieje, mogę go przetestować i dowiedzieć się, jak to działa. Do tego czasu, kto wie, co faktycznie zaimplementują przeglądarki? Chyba że masz najnowsze informacje, które wręcz przeciwnie ...
jamess
@jamess Prawda, że ​​wciąż jest w fazie projektowania .. jednak najnowsze FF i chrome wydają się w pełni go wspierać .. Nie jestem pewien, czy to stabilność… Mozilla Docs W każdym razie chciałem, aby było to o wiele łatwiejsze do znalezienia jeśli to była odpowiedź niż komentarz .. to zadzwoń :)
pravin
@pravin - w momencie, gdy opublikowałem mój komentarz, nie został nigdzie zaimplementowany. Właśnie przetestowałem w Firefox i Chrome: Promise.allSettlednie jest zaimplementowany w Firefox, ale wydaje się, że istnieje w Chrome. To, że doktorzy mówią, że jest zaimplementowane, nie oznacza, że ​​tak naprawdę jest zaimplementowane. Nie zamierzam go używać w najbliższym czasie.
jamess
0

Alternatywnie, jeśli masz przypadek, w którym nie zależy ci szczególnie na wartościach rozwiązanych obietnic, gdy występuje jedna awaria, ale nadal chcesz, aby się spełniły, możesz zrobić coś takiego, co rozwiązuje się z obietnicami normalnie, gdy wszyscy odnoszą sukces i odrzucają obietnice, których nie dotrzymują:

function promiseNoReallyAll (promises) {
  return new Promise(
    async (resolve, reject) => {
      const failedPromises = []

      const successfulPromises = await Promise.all(
        promises.map(
          promise => promise.catch(error => {
            failedPromises.push(error)
          })
        )
      )

      if (failedPromises.length) {
        reject(failedPromises)
      } else {
        resolve(successfulPromises)
      }
    }
  )
}
Eric
źródło
0

Zawsze możesz zawinąć funkcje zwracające obietnicę w taki sposób, że wychwytują awarię i zwracają zamiast tego uzgodnioną wartość (np. Error.message), więc wyjątek nie zwinie się aż do funkcji Promise.all i ją wyłączy.

async function resetCache(ip) {

    try {

        const response = await axios.get(`http://${ip}/resetcache`);
        return response;

    }catch (e) {

        return {status: 'failure', reason: 'e.message'};
    }

}
Tamir Nakar
źródło
0

Znalazłem sposób (obejście), aby to zrobić bez synchronizacji.

Jak już wspomniano wcześniej, nie Promise.allma żadnego.

więc ... Użyj załączonej obietnicy, aby złapać i zmusić rozwiązanie.


      let safePromises = originalPrmises.map((imageObject) => {
            return new Promise((resolve) => {
              // Do something error friendly
              promise.then(_res => resolve(res)).catch(_err => resolve(err))
            })
        })
    })

    // safe
    return Promise.all(safePromises)
Juan Sebastian Contreras Aceve
źródło
0

Musisz wiedzieć, jak rozpoznać błąd w wynikach. Jeśli nie masz standardowego oczekiwanego błędu, sugeruję przeprowadzenie transformacji dla każdego błędu w bloku catch, który umożliwia jego identyfikację w wynikach.

try {
  let resArray = await Promise.all(
    state.routes.map(route => route.handler.promiseHandler().catch(e => e))
  );

  // in catch(e => e) you can transform your error to a type or object
  // that makes it easier for you to identify whats an error in resArray
  // e.g. if you expect your err objects to have e.type, you can filter
  // all errors in the array eg
  // let errResponse = resArray.filter(d => d && d.type === '<expected type>')
  // let notNullResponse = resArray.filter(d => d)

  } catch (err) {
    // code related errors
  }
Anthony Awuley
źródło
0

Nie jest to najlepszy sposób na zapisywanie błędów, ale zawsze możesz ustawić wszystko na tablicę dla promiseAll i zapisać uzyskane wyniki w nowych zmiennych.

Jeśli używasz GraphQL, musisz przetworzyć odpowiedź niezależnie od tego, a jeśli nie znajdzie poprawnego odwołania, spowoduje to awarię aplikacji, zawężając zakres problemu

const results = await Promise.all([
  this.props.client.query({
    query: GET_SPECIAL_DATES,
  }),
  this.props.client.query({
    query: GET_SPECIAL_DATE_TYPES,
  }),
  this.props.client.query({
    query: GET_ORDER_DATES,
  }),
]).catch(e=>console.log(e,"error"));
const specialDates = results[0].data.specialDates;
const specialDateTypes = results[1].data.specialDateTypes;
const orderDates = results[2].data.orders;
Vincent Tang
źródło
-1

Tak Promise.alljest zaprojektowany do pracy. Jeśli jest jedna obietnica reject(), cała metoda natychmiast zawodzi.

Są przypadki użycia, w których można chcieć, aby Promise.allobietnice dopuszczające się nie spełniły. Aby tak się stało, po prostu nie używaj żadnych reject()oświadczeń w obietnicy. Jednak, aby upewnić się, że twoja aplikacja / skrypt nie zawiesza się w przypadku, gdy żadna bazowa obietnica nigdy nie otrzyma odpowiedzi, musisz poświęcić jej czas.

function getThing(uid,branch){
    return new Promise(function (resolve, reject) {
        xhr.get().then(function(res) {
            if (res) {
                resolve(res);
            } 
            else {
                resolve(null);
            }
            setTimeout(function(){reject('timeout')},10000)
        }).catch(function(error) {
            resolve(null);
        });
    });
}
Ronnie Royston
źródło
oto odpowiedź: stackoverflow.com/questions/31424561/...
Humoyun Ahmad
Nieużywanie reject()w obietnicy jest w porządku, ale co zrobić, jeśli trzeba skorzystać z obietnic innej biblioteki?
Dan Dascalescu
-8

Napisałem bibliotekę npm, aby uporać się z tym problemem piękniej. https://github.com/wenshin/promiseallend

zainstalować

npm i --save promiseallend

2017-02-25 nowy API, to nie jest złamanie obietnicy zasad

const promiseAllEnd = require('promiseallend');

const promises = [Promise.resolve(1), Promise.reject('error'), Promise.resolve(2)];
const promisesObj = {k1: Promise.resolve(1), k2: Promise.reject('error'), k3: Promise.resolve(2)};

// input promises with array
promiseAllEnd(promises, {
    unhandledRejection(error, index) {
        // error is the original error which is 'error'.
        // index is the index of array, it's a number.
        console.log(error, index);
    }
})
    // will call, data is `[1, undefined, 2]`
    .then(data => console.log(data))
    // won't call
    .catch(error => console.log(error.detail))

// input promises with object
promiseAllEnd(promisesObj, {
    unhandledRejection(error, prop) {
        // error is the original error.
        // key is the property of object.
        console.log(error, prop);
    }
})
    // will call, data is `{k1: 1, k3: 2}`
    .then(data => console.log(data))
    // won't call
    .catch(error => console.log(error.detail))

// the same to `Promise.all`
promiseAllEnd(promises, {requireConfig: true})
    // will call, `error.detail` is 'error', `error.key` is number 1.
    .catch(error => console.log(error.detail))

// requireConfig is Array
promiseAllEnd(promises, {requireConfig: [false, true, false]})
    // won't call
    .then(data => console.log(data))
    // will call, `error.detail` is 'error', `error.key` is number 1.
    .catch(error => console.log(error.detail))

// requireConfig is Array
promiseAllEnd(promises, {requireConfig: [true, false, false]})
    // will call, data is `[1, undefined, 2]`.
    .then(data => console.log(data))
    // won't call
    .catch(error => console.log(error.detail))

———————————————————————————————

Stare złe API, nie używaj go!

let promiseAllEnd = require('promiseallend');

// input promises with array
promiseAllEnd([Promise.resolve(1), Promise.reject('error'), Promise.resolve(2)])
    .then(data => console.log(data)) // [1, undefined, 2]
    .catch(error => console.log(error.errorsByKey)) // {1: 'error'}

// input promises with object
promiseAllEnd({k1: Promise.resolve(1), k2: Promise.reject('error'), k3: Promise.resolve(2)})
    .then(data => console.log(data)) // {k1: 1, k3: 2}
    .catch(error => console.log(error.errorsByKey)) // {k2: 'error'}
wenshin
źródło
Jak to działa? Pokaż i wyjaśnij swoją implementację funkcji.
Bergi
Napisałem nową podobną logikę Promise.all. Ale zbierze wszystkie dane i błędy każdej obietnicy. obsługuje także wprowadzanie obiektów, to nie jest punkt. po zebraniu wszystkich danych i błędów zastępuję promise.thenmetodę postępowania z zarejestrowanymi wywołaniami zwrotnymi, które obejmują odrzucenie i spełnienie. Szczegółowe informacje można znaleźć w kodzie
wenshin
Uh, ten kod wywoła zarówno przekaźniki, jak onFulfilledi onRejectedprogramy obsługi, które są przekazywane then?
Bergi
Tak, tylko wtedy, gdy obiecywać status mix fulfilledi rejected. Ale tak naprawdę powoduje, że trudny problem jest zgodny ze wszystkimi obietnicami użycia normalnie, jak onFulfilledi onRejectedwszystkie zwracają Promise.reject()lub Promise.resolve(). Jak dotąd nie jestem pewien, jak to rozwiązać, czy ktoś ma lepszy pomysł? Najlepszą odpowiedzią na ten problem jest to, że nie może on filtrować danych i błędów w środowisku przeglądarki.
wenshin
Czy musimy zainstalować moduł npm z menedżerem pakietów pip python?
sevenfourk