为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

汪汪一只猫 2019-06-01 14:01:41
等到所有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没有为此留出任何空间,建议的处理模式是什么,而不使用承诺库?
查看完整描述

3 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

当然,你只需要一个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");});


查看完整回答
反对 回复 2019-06-01
?
LEATH

TA贡献1936条经验 获得超6个赞

类似的答案,但更符合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)))

  .then(results => console.log(results)) // 1,Error: 2,3

  .catch(e => console.log(e));



const console = { log: msg => div.innerHTML += msg + "<br>"};

<div id="div"></div>

根据返回值的类型,通常可以很容易地区分错误(例如,使用undefined因为“不关心”,typeof对于普通的非对象值,result.messageresult.toString().startsWith("Error:")(等等)


查看完整回答
反对 回复 2019-06-01
?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

Benjamin的回答为解决这个问题提供了一个很大的抽象,但我希望得到一个抽象程度较低的解决方案。解决这个问题的明确方法是简单地调用.catch在内部承诺,并返回错误从他们的回调。

let a = new Promise((res, rej) => res('Resolved!')),
    b = new Promise((res, rej) => rej('Rejected!')),
    c = a.catch(e => { console.log('"a" failed.'); return e; }),
    d = b.catch(e => { console.log('"b" failed.'); return e; });Promise.all([c, d])
  .then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
  .catch(err => console.log('Catch', err));Promise.all([a.catch(e => e), b.catch(e => e)])
  .then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
  .catch(err => console.log('Catch', err));

更进一步,您可以编写一个一般的捕获处理程序,如下所示:

const catchHandler = error => ({ payload: error, resolved: false });

那你就可以

> Promise.all([a, b].map(promise => promise.catch(catchHandler))
    .then(results => console.log(results))
    .catch(() => console.log('Promise.all failed'))< [ 'Resolved!',  { payload: Promise, resolved: false } ]

这方面的问题是,所捕获的值将具有与未捕获值不同的接口,因此,为了清理这些值,您可能会执行以下操作:

const successHandler = result => ({ payload: result, resolved: true });

所以现在你可以这么做了:

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
    .then(results => console.log(results.filter(result => result.resolved))
    .catch(() => console.log('Promise.all failed'))< [ 'Resolved!' ]

为了保持干燥,你可以找到本杰明的答案:

const reflect = promise => promise  .then(successHandler)
  .catch(catchHander)

现在看上去就像

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
    .then(results => console.log(results.filter(result => result.resolved))
    .catch(() => console.log('Promise.all failed'))< [ 'Resolved!' ]

第二个解决方案的好处是它的抽象和干燥。缺点是,您有更多的代码,您必须记住,您的所有承诺,以使事情一致。

我将我的解决方案描述为明确和亲吻,但实际上不那么健壮。接口不能保证您确切地知道承诺是成功还是失败。

例如,您可能拥有以下内容:

const a = Promise.resolve(new Error('Not beaking, just bad'));const b = Promise.reject(new Error('This actually didnt work'));

这不会被抓住的a.catch,所以

> Promise.all([a, b].map(promise => promise.catch(e => e))
    .then(results => console.log(results))< [ Error, Error ]

不知道哪一个是致命的,哪个不是。如果这很重要,那么您将希望执行和接口,以跟踪它是否成功(其中reflect)。

如果您只想优雅地处理错误,那么只需将错误视为未定义的值:

> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
    .then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))< [ 'Resolved!' ]

在我的例子中,我不需要知道错误或者它是如何失败的-我只是关心我是否有这个价值。我将让生成承诺的函数担心记录特定的错误。

const apiMethod = () => fetch()
  .catch(error => {
    console.log(error.message);
    throw error;
  });

这样,如果需要,应用程序的其他部分可以忽略它的错误,如果需要,可以将其视为一个未定义的值。

我希望我的高级函数能够安全地失效,而不必担心它的依赖项失败的细节,而且当我不得不做这种权衡时,我更喜欢亲吻而不是干燥-这就是我选择不使用的最终原因。reflect.


查看完整回答
反对 回复 2019-06-01
  • 3 回答
  • 0 关注
  • 402 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信