Обработка ошибок в обещании.все
у меня есть множество обещаний, которые я решаю с обещанием.все(arrayOfPromises);
Я продолжаю цепочку обещаний. Выглядит примерно так
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();
});
Я хочу добавить оператор catch для обработки отдельного обещания в случае его ошибок, но когда я пытаюсь, обещаю.all возвращает первую ошибку, которую он находит (игнорирует остальные), а затем я не могу получить данные из остальных обещаний в массиве (это не ошибка).
Я пробовал делать что-то вроде ..
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();
});
но это не решает.
спасибо!
--
Edit:
то, что ответы ниже сказали, было полностью правдой, код был нарушен по другим причинам. В случае, если кто-то заинтересован, это решение я в конечном итоге ...
Node Express Server Chain
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;
})
};
вызов API (маршрут.асинхронный вызов)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
поставить .поймать за обещание.все раньше этот.затем, похоже, служили цели ловли любых ошибок из исходных обещаний, но затем возвращали весь массив к следующему .тогда
спасибо!
8 ответов:
Promise.all
- это все или ничего. Он разрешает один раз все обещания в массиве resolve, или отклонить, как только один из них отвергает. Другими словами, он либо разрешает массив всех разрешенных значений, либо отклоняет с одной ошибкой.В некоторых библиотеках есть что-то под названием
Promise.when
, который, как я понимаю, вместо этого будет ждать все обещает в массиве либо разрешить, либо отклонить, но я не знаком с ним, и его нет ES6.код
Я согласен с другими, что исправление должно работать. Он должен разрешаться с помощью массива, который может содержать сочетание успешных значений и объектов ошибок. Необычно передавать объекты ошибок в пути успеха, но предполагая, что ваш код ожидает их, я не вижу проблем с этим.
единственная причина, по которой я могу думать о том, почему он "не разрешит", заключается в том, что он не работает в коде, который Вы нам не показываете, и причина, по которой вы не видите любое сообщение об ошибке связано с тем, что эта цепочка обещаний не заканчивается окончательным уловом (насколько Вы нам показываете в любом случае).
Я взял на себя смелость разложить "существующую цепь" из вашего примера и завершить цепь с уловом. Это может быть неправильно для вас, но для людей, читающих это, важно всегда либо возвращать, либо прекращать цепочки, либо потенциальные ошибки, даже ошибки кодирования, будут скрыты (что, как я подозреваю, произошло здесь):
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 });
продолжить
Promise.all
цикл (даже когда обещание отклоняется) я написал функцию полезности, которая называетсяexecuteAllPromises
. Эта служебная функция возвращает объект сresults
иerrors
.идея в том, что все обещания вы передаете
executeAllPromises
будет обернут в новое обещание, которое всегда будет решать. Новое обещание решает с массивом, который имеет 2 пятна. Первое место содержит разрешающее значение (если оно есть) , а второе место сохраняет ошибку (если завернутое обещание отходы.)в качестве заключительного шага
executeAllPromises
накапливает все значения завернутых обещаний и возвращает конечный объект с массивом дляresults
и массив заerrors
.вот код:
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}`); });
Если вы используете библиотеку q https://github.com/kriskowal/q он имеет Q. allSettled() метод, который может решить эту проблему вы можете обрабатывать каждое обещание в зависимости от его состояния либо заполнено, либо отклонено так что
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(); });
мы должны написать пользовательский обещание.все.)( Вот решение, которое я использую в своем проекте. Ошибка будет возвращена как обычный результат. После того, как все обещания закончатся, мы можем отфильтровать ошибку.
const Promise_all = promises => { return new Promise((resolve, reject) => { const results = []; let count = 0; promises.forEach((promise, idx) => { promise .catch(err => { return err; }) .then(valueOrError => { results[idx] = valueOrError; count += 1; if (count === promises.length) resolve(results); }); }); }); }; const results = await Promise_all(promises) const validResults = results.filter(result => !(result instanceof Error));
для тех, кто использует ES8, которые спотыкаются здесь, вы можете сделать что-то вроде следующего, используя асинхронные функции:
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);
вот так
Promise.all
предназначен для работы. Если одно обещаниеreject()
' s, весь метод сразу терпит неудачу.есть случаи использования, когда можно было бы иметь
Promise.all
учитывая обещания потерпеть неудачу. Чтобы это произошло, просто не используйте никакихreject()
заявления в свое обещание. Однако, чтобы убедиться, что ваше приложение / скрипт не замерзает в случае какого-либо одного базового обещания никогда получает ответ, вам нужно поставить тайм-аут на него.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); }); }); }
мы можем обрабатывать отказ на уровне отдельных обещаний, поэтому, когда мы получим результаты в нашем массиве результатов, индекс массива, который был отклонен, будет неопределенным, и мы можем обрабатывать эту ситуацию по мере необходимости. И использовать оставшиеся результаты.
здесь я отклонил первое обещание, поэтому оно не определено, но мы можем использовать результат второго обещания, который находится в индексе 1.
var 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) => { res("func2");}).catch(err => { console.log(`error handled ${err}`); }); }
Я написал библиотеку npm, чтобы справиться с этой проблемой более красиво. https://github.com/wenshin/promiseallend
установить
npm i --save promiseallend
2017-02-25 новый api, это не нарушает принципы обещания
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))
--------------------------------
старый плохой api, не используйте его!
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'}