Разрешить промис после того, как все внутренние одновременные промисы разрешены или отклонены

Я ищу что-то похожее на Promise.all, которое будет продолжать одновременно разрешать промисы даже в том случае, если одно или несколько промисов отклоняются или выдают ошибку. Каждый запрос не зависит от другого запроса.

Близко к тому, что я хочу — см. комментарии

function fetchRequest (request) {
  return new Promise(function (resolve, reject) {
    fetch(request)
    .then(function(response) {
      return response.text();      

    }).then(function (responseXML) {
      //Do something here. Maybe add data to dom
      resolve(responseXML);

    }).catch(function (err) {
      reject(new Error(err));
    }
}

function promiseRequests (requests) {
  var result = Promise.resolve();

  for (var i = 0; i < requests.length; i++) {
    result = fetchRequest(requests[i])
  }

  //This is wrong as it will resolve when the last promise in the requests array resolves
  // - not when all requests resolve
  resolve(result);
}

promiseRequests(['url1.com', 'url2.com']).then(function (data) {
  console.log('All requests finished');
  //optionally have data be an array of resolved and rejected promises
});

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

Работает, но похоже на неправильное использование разрешения

function fetchRequest (request) {
  return new Promise(function (resolve, reject) {
    fetch(request)
    .then(function(response) {
      return response.text();      

    }).then(function (responseXML) {
      resolve(responseXML);

    }).catch(function (err) {
      resolve();
    }
}

Promise.all([fetchRequest('url1.com'), fetchRequest('url2.com')]).then(function (data) {
  console.log('All requests finished', data); //data could be ['resultXML', undefined]
});

Пожалуйста, только нативные ответы API обещаний es6 спасибо.


person Calummm    schedule 19.06.2015    source источник
comment
Прежде всего, избегайте антишаблона конструктора промисов!   -  person Bergi    schedule 19.06.2015
comment
Это также лишает меня возможности использовать сброшенные ошибки. - тогда почему бы не просто resolve(err)? Как вы собираетесь их использовать? Как бы вы хотели различать исполнение и отказ?   -  person Bergi    schedule 19.06.2015
comment
Ах я вижу. После прочтения вашей ссылки, Берги, я думаю, что мое понимание обещаний наконец-то изменилось. Я думаю, что ответ Доменика лечит симптом моей проблемы, но ответ Берги устраняет основную причину.   -  person Calummm    schedule 19.06.2015


Ответы (2)


Мне удалось использовать Promise.all вместе, только когда-либо разрешая обещания fetchRequest

Это в основном путь. В ES6 нет вспомогательной функции, такой как allSettled (Q) или settle (Bluebird 2.x) для этого случае, поэтому нам нужно будет использовать Promise.all похоже на то, что ты сделал. Для этого у Bluebird даже есть специальная утилита .reflect().

Однако в случае отклонения вы бы разрешили их не с помощью undefined, а с помощью некоторого полезного значения, позволяющего идентифицировать ошибки.

function promiseRequests(requests) {
  return Promise.all(requests.map(request => {
    return fetch(request).then(res => {
      return {value:res};
    }, err => {
      return {reason:err};
    });
  }));
}
person Bergi    schedule 19.06.2015
comment
См. )) в конце Promise.all() . Вопрос: Обрабатывает ли этот шаблон случай с обработчиком ошибок Overly Keen, описанный на taoofcode.net/promise-anti-patterns ? - person guest271314; 19.06.2015
comment
Обратите внимание: без return внутри .map() в fetch , promiseRequests кажется, что возвращаются undefined для Promise значений jsfiddle.net/gn81Lf6u/2 , jsfiddle.net/gn81Lf6u/3 - person guest271314; 19.06.2015
comment
@guest271314: Это стрелочная функция, где возврат неявный :-) Но я отредактировал для ясности (и согласованности с двумя другими выражениями, где невозможно краткое тело) - person Bergi; 19.06.2015
comment
Это стрелочная функция, где возврат неявный :-) Пробовал стрелочную функцию в ночное время без return перед fetch ; казалось, возвращает undefined для Promise значений из promiseRequests jsfiddle.net/gn81Lf6u/5 , jsfiddle.net/gn81Lf6u/7 - person guest271314; 19.06.2015
comment
@guest271314: Вы не должны использовать фигурные скобки {}, если хотите неявный возврат. Это работает только для кратких тел, а не для функциональных тел. - person Bergi; 19.06.2015
comment
Пробовал читать страницу MDN по стрелочной функции, но не смог вернуть те же результаты из .map() без фигурных скобок. Если вопрос не слишком далеко от исходного вопроса, можете ли вы привести пример с использованием .map без {} для возврата того же результата? - person guest271314; 19.06.2015
comment
@guest271314: Простой пример: [1,2,3].map(x => x+1). Должен дать цифры. Может быть, FF или Chrome еще не поддерживают это, я не знаю, но это стандартный синтаксис. Да, для дальнейших вопросов вы должны рассмотреть возможность их публикации :-) - person Bergi; 19.06.2015

По сути, вы просите способ проглотить любые ошибки. Таким образом, такая функция будет вашим лучшим выбором:

function swallow(p) {
  // transforms rejected promises into promises fulfilled with undefined
  return p.catch(function () { });
}

Вы бы использовали его следующим образом:

Promise.all([swallow(fetch('url1.com')), swallow(fetch('url2.com'))]).then(function (data) {
  console.log('All requests finished', data); //data could be ['resultXML', undefined]
});

или даже

 const promises = ['url1.com', 'url2.com'].map(fetch).map(swallow);
 Promise.all(promises).then(function (data) {
   // ...
 });
person Domenic    schedule 19.06.2015