假设我正在构建一个典型的RSS阅读器。我正在解析几个feed并将所有剧集写入DB:
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))
processFeed()
processEpisode()
processFeed()
醇>
但是,如果针对某些Feed的某些剧集的fetchMetadata(episode)
会引发拒绝,所有该链条会被破坏并立即落入全球.catch(err=> console.log(err))
。
在正常情况下,我们需要对未经处理的剧集做一些事情,但最少应该正常处理。一种解决方案是将processEpisode()
包装在外部Promise中并就地处理。
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()
之后在更高级别的Promise链中有另一个元素,它将失败'因为processEpisode
将解析true
而不是真实结果。
有没有一种优雅的方法来解决这些问题?我在Bluebird中查看finally
语句,但我不确定这是最好的方法。
谢谢!
答案 0 :(得分:3)
只需将myRpackage::my_R_function
处理程序直接放在.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()
处理程序只会在拒绝承诺或抛出的情况下拒绝承诺。