2016-05-11 3 views
1

Предположим, что я строю типичный RSS-ридер. Я разбор несколько каналов и записать все свои эпизоды к БД:Как обращаться с отклонениями в Bluebird, не нарушая цепочку обещаний?

const processEpisode = (episode)=> 
    fetchMetadata(episode) 
    .then(parseMetadata) 
    .then(writeToDb) 

const processFeed = (feed)=> 
    fetchEpisodes(feed) // returns [Episode] 
    .map(processEpisode, { concurrency: 3 }) 

// main 
getFeeds() // returns [Feed] 
.map(processFeed, { concurrency: 3 }) 
.catch(err=> console.log(err)) 
  1. Мы получаем все каналы
  2. Для каждого кормления испускают processFeed()
  3. Для каждого эпизода выделяет processEpisode() из processFeed()

Однако, если fetchMetadata(episode) для некоторого эпизода для некоторого фида выбрасывает отказ, все цепочка разбивается и сразу попадает в глобальную .catch(err=> console.log(err)).

В нормальной ситуации нам нужно что-то сделать с необработанным эпизодом, но наименьшее должно обрабатываться нормально. Одним из решений является обертка processEpisode() в наружном обещании и ручке на месте.

const processEpisode = (episode)=> 
    new Promise((resolve, reject)=> { 
    fetchMetadata(episode) 
    .then(parseMetadata) 
    .then(writeToDb) 
    .then((result)=> resolve(result)) 
    .catch((err)=> { 
     // something bad happened 
     // process and error, but resolve a fullfilled Promise! 
     resolve(true) 
    }) 
    }) 

Однако, я полагаю, это очевидный анти-шаблон. И если после processEpisode() есть еще один элемент в цепочке обещаний более высокого уровня, он не сработает, потому что processEpisode решит true вместо реального результата.

Есть ли элегантный способ решения таких проблем? Я просматриваю заявление finally в Bluebird, но я не уверен, что это лучший способ.

Спасибо!

ответ

3

Просто поместите .catch() обработчика непосредственно на processFeed(), так что вы можете обработать отказ локально и превратить его в разрешаемом обещание, которое позволит всему остальному продолжить:

// main 
getFeeds() // returns [Feed] 
.map(function(item, index, length) { 
    return processFeed(item, index, length).catch(function(reason) { 
     // do whatever you want to here, this will "handle" the rejection 
     // and turn it into a resolved promise 
     // whatever you return here will become the resolved value 
    }); 
}, { concurrency: 3 }) 
.catch(err=> console.log(err)) 

Примечания: Вам не нужен дополнительные упаковка обещание. Добавление обработчика .catch() и возврат нормального значения из обработчика .catch() превратят отклоненное обещание в разрешенное обещание, поскольку отклонение считается «обработанным» в этой точке. Независимо от того, какое значение вы возвращаете из обработчика .catch(), становится разрешенным значением родительского обещания.

A .catch() Обработчик будет удерживать обещание только в том случае, если оно возвращает отклоненное обещание или броски.

+0

Пробовал это прямо перед вашим комментарием, и это сработало :) Спасибо за подтверждение. Отметив это как решение. – f1nn

Смежные вопросы