等到所有ES6承诺完成,甚至是被拒绝的承诺

等到所有ES6承诺完成,甚至是被拒绝的承诺

假设我有一组正在发出网络请求的承诺,其中一项承诺将失败:

// http://does-not-exist will throw a TypeErrorvar arr = [ fetch('index.html'), fetch('http://does-not-exist') ]Promise.all(arr)
  .then(res => console.log('success', res))
  .catch(err => console.log('error', err)) // This is executed

假设我想等到所有这些都完成,不管是否失败。可能有一个网络错误的资源,我可以生活没有,但如果我可以得到,我想在我继续之前。我想优雅地处理网络故障。

Promises.all没有为此留出任何空间,建议的处理模式是什么,而不使用承诺库?


汪汪一只猫
浏览 403回答 3
3回答

拉丁的传说

当然,你只需要一个reflect:const reflect = p => p.then(v => ({v, status: "fulfilled" }),                             e => ({e, status: "rejected" }));reflect(promise).then((v => {     console.log(v.status);});或与ES5:function reflect(promise){     return promise.then(function(v){ return {v:v, status: "resolved" }},                         function(e){ return {e:e, status: "rejected" }});}reflect(promise).then(function(v){     console.log(v.status);});或者在你的例子中:var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]Promise.all(arr.map(reflect)).then(function(results){     var success = results.filter(x => x.status === "resolved");});

LEATH

类似的答案,但更符合ES6的习惯:const a = Promise.resolve(1);const b = Promise.reject(new Error(2));const c = Promise.resolve(3);Promise.all([a, b, c].map(p => p.catch(e => e)))&nbsp; .then(results => console.log(results)) // 1,Error: 2,3&nbsp; .catch(e => console.log(e));const console = { log: msg => div.innerHTML += msg + "<br>"};<div id="div"></div>根据返回值的类型,通常可以很容易地区分错误(例如,使用undefined因为“不关心”,typeof对于普通的非对象值,result.message,&nbsp;result.toString().startsWith("Error:")(等等)

宝慕林4294392

Benjamin的回答为解决这个问题提供了一个很大的抽象,但我希望得到一个抽象程度较低的解决方案。解决这个问题的明确方法是简单地调用.catch在内部承诺,并返回错误从他们的回调。let&nbsp;a&nbsp;=&nbsp;new&nbsp;Promise((res,&nbsp;rej)&nbsp;=>&nbsp;res('Resolved!')), &nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;new&nbsp;Promise((res,&nbsp;rej)&nbsp;=>&nbsp;rej('Rejected!')), &nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;=&nbsp;a.catch(e&nbsp;=>&nbsp;{&nbsp;console.log('"a"&nbsp;failed.');&nbsp;return&nbsp;e;&nbsp;}), &nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;=&nbsp;b.catch(e&nbsp;=>&nbsp;{&nbsp;console.log('"b"&nbsp;failed.');&nbsp;return&nbsp;e;&nbsp;});Promise.all([c,&nbsp;d]) &nbsp;&nbsp;.then(result&nbsp;=>&nbsp;console.log('Then',&nbsp;result))&nbsp;//&nbsp;Then&nbsp;["Resolved!",&nbsp;"Rejected!"] &nbsp;&nbsp;.catch(err&nbsp;=>&nbsp;console.log('Catch',&nbsp;err));Promise.all([a.catch(e&nbsp;=>&nbsp;e),&nbsp;b.catch(e&nbsp;=>&nbsp;e)]) &nbsp;&nbsp;.then(result&nbsp;=>&nbsp;console.log('Then',&nbsp;result))&nbsp;//&nbsp;Then&nbsp;["Resolved!",&nbsp;"Rejected!"] &nbsp;&nbsp;.catch(err&nbsp;=>&nbsp;console.log('Catch',&nbsp;err));更进一步,您可以编写一个一般的捕获处理程序,如下所示:const&nbsp;catchHandler&nbsp;=&nbsp;error&nbsp;=>&nbsp;({&nbsp;payload:&nbsp;error,&nbsp;resolved:&nbsp;false&nbsp;});那你就可以>&nbsp;Promise.all([a,&nbsp;b].map(promise&nbsp;=>&nbsp;promise.catch(catchHandler)) &nbsp;&nbsp;&nbsp;&nbsp;.then(results&nbsp;=>&nbsp;console.log(results)) &nbsp;&nbsp;&nbsp;&nbsp;.catch(()&nbsp;=>&nbsp;console.log('Promise.all&nbsp;failed'))<&nbsp;[&nbsp;'Resolved!',&nbsp;&nbsp;{&nbsp;payload:&nbsp;Promise,&nbsp;resolved:&nbsp;false&nbsp;}&nbsp;]这方面的问题是,所捕获的值将具有与未捕获值不同的接口,因此,为了清理这些值,您可能会执行以下操作:const&nbsp;successHandler&nbsp;=&nbsp;result&nbsp;=>&nbsp;({&nbsp;payload:&nbsp;result,&nbsp;resolved:&nbsp;true&nbsp;});所以现在你可以这么做了:>&nbsp;Promise.all([a,&nbsp;b].map(result&nbsp;=>&nbsp;result.then(successHandler).catch(catchHandler)) &nbsp;&nbsp;&nbsp;&nbsp;.then(results&nbsp;=>&nbsp;console.log(results.filter(result&nbsp;=>&nbsp;result.resolved)) &nbsp;&nbsp;&nbsp;&nbsp;.catch(()&nbsp;=>&nbsp;console.log('Promise.all&nbsp;failed'))<&nbsp;[&nbsp;'Resolved!'&nbsp;]为了保持干燥,你可以找到本杰明的答案:const&nbsp;reflect&nbsp;=&nbsp;promise&nbsp;=>&nbsp;promise&nbsp;&nbsp;.then(successHandler) &nbsp;&nbsp;.catch(catchHander)现在看上去就像>&nbsp;Promise.all([a,&nbsp;b].map(result&nbsp;=>&nbsp;result.then(successHandler).catch(catchHandler)) &nbsp;&nbsp;&nbsp;&nbsp;.then(results&nbsp;=>&nbsp;console.log(results.filter(result&nbsp;=>&nbsp;result.resolved)) &nbsp;&nbsp;&nbsp;&nbsp;.catch(()&nbsp;=>&nbsp;console.log('Promise.all&nbsp;failed'))<&nbsp;[&nbsp;'Resolved!'&nbsp;]第二个解决方案的好处是它的抽象和干燥。缺点是,您有更多的代码,您必须记住,您的所有承诺,以使事情一致。我将我的解决方案描述为明确和亲吻,但实际上不那么健壮。接口不能保证您确切地知道承诺是成功还是失败。例如,您可能拥有以下内容:const&nbsp;a&nbsp;=&nbsp;Promise.resolve(new&nbsp;Error('Not&nbsp;beaking,&nbsp;just&nbsp;bad'));const&nbsp;b&nbsp;=&nbsp;Promise.reject(new&nbsp;Error('This&nbsp;actually&nbsp;didnt&nbsp;work'));这不会被抓住的a.catch,所以>&nbsp;Promise.all([a,&nbsp;b].map(promise&nbsp;=>&nbsp;promise.catch(e&nbsp;=>&nbsp;e)) &nbsp;&nbsp;&nbsp;&nbsp;.then(results&nbsp;=>&nbsp;console.log(results))<&nbsp;[&nbsp;Error,&nbsp;Error&nbsp;]不知道哪一个是致命的,哪个不是。如果这很重要,那么您将希望执行和接口,以跟踪它是否成功(其中reflect)。如果您只想优雅地处理错误,那么只需将错误视为未定义的值:>&nbsp;Promise.all([a.catch(()&nbsp;=>&nbsp;undefined),&nbsp;b.catch(()&nbsp;=>&nbsp;undefined)]) &nbsp;&nbsp;&nbsp;&nbsp;.then((results)&nbsp;=>&nbsp;console.log('Known&nbsp;values:&nbsp;',&nbsp;results.filter(x&nbsp;=>&nbsp;typeof&nbsp;x&nbsp;!==&nbsp;'undefined')))<&nbsp;[&nbsp;'Resolved!'&nbsp;]在我的例子中,我不需要知道错误或者它是如何失败的-我只是关心我是否有这个价值。我将让生成承诺的函数担心记录特定的错误。const&nbsp;apiMethod&nbsp;=&nbsp;()&nbsp;=>&nbsp;fetch() &nbsp;&nbsp;.catch(error&nbsp;=>&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log(error.message); &nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;error; &nbsp;&nbsp;});这样,如果需要,应用程序的其他部分可以忽略它的错误,如果需要,可以将其视为一个未定义的值。我希望我的高级函数能够安全地失效,而不必担心它的依赖项失败的细节,而且当我不得不做这种权衡时,我更喜欢亲吻而不是干燥-这就是我选择不使用的最终原因。reflect.
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript