ES6 Promise.all()错误句柄 - 需要.settle()吗? [英] ES6 Promise.all() error handle - Is .settle() needed?

查看:233
本文介绍了ES6 Promise.all()错误句柄 - 需要.settle()吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个 Promise.all()来处理两个承诺。如果一个承诺产生错误,但另一个解决方案,我希望能够根据 Promise.all()已经解决的情况处理错误。 / p>

ES6承诺缺少解决方法,我假设有一个很好的理由。但是我不禁想到, .settle()方法会使这个问题对我来说容易很多。



我正在以错误的方式进行这种做法,还是以一种解决方法来扩展ES6 Promises在这里做的正确的事情?



我如何思考的一个例子使用 .settle()

  Promise.all([Action1 ,Action2])
.settle(function(arrayOfSettledValues)
// if 1 failed but not 2,handle
// if 2 failed but not 1,handle
// etc ....


解决方案


我是这样做的错误的方式还是扩展ES6 Promises
与一个解决方法在这里做的正确的事情?


您不能直接使用 Promise.all()来生成 .settle()类型行为,无论是否拒绝,都会得到所有结果,因为 Promise.all()是快速失败并在第一个承诺拒绝后立即返回,只返回拒绝原因,没有其他结果。



所以,需要不同的东西。通常情况下,解决这个问题的最简单的方法是只需添加一个 .then()处理程序到任何操作创建你的承诺数组,以便它捕获任何拒绝,并使它们达到履行的承诺,具有一定的特定价值,你可以测试。但是,这种类型的解决方案是依赖于实现的,因为它取决于您正在返回哪种类型的值,因此不是完全一般的。



如果您想要一个通用解决方案,那么像 .settle()这样的东西是非常有用的。



你不能使用结构: p>

  Promise.all([...])。sett(...)然后(...); 

因为 Promise.all()你通过的第一个承诺拒绝,它只返回拒绝。 code code code code [...])。然后(...);

如果你有兴趣,这里是一个相当简单的 Promise .settle()

  // ES6版本的结算
Promise.settle =函数(promises){
函数PromiseInspection(已履行,val){
return {
isFulfilled:function(){
return fulfilled;
},isRejected:function(){
return!
},isPending:function(){
//这里创建的PromiseInspection对象永远不会挂起
return false;
},value:function(){
if(!fulfilled){
throw new Error(Can not call .value()on a promise that not not fulfilled);
}
return val;
},原因:function(){
if(fulfillilled){
throw new Error(Can not call .reason()on a promise that metilled);
}
return val;
}
};
}

返回Promise.all(promises.map(function(p)){
//确保任何值都包含在承诺中
返回Promise.resolve (p).then(function(val){
return new PromiseInspection(true,val);
},function(err){
return new PromiseInspection(false,err);
});
}));
}

在这个实现中, Promise.settle() / code>将永远解决(永远不会拒绝),并使用 PromiseInspection 对象的数组解析,允许您测试每个单独的结果,以查看其是否已解决或拒绝每个人的价值或理由是什么。通过在传递给每个承诺的承诺中附加一个 .then()处理程序,它可以处理来自该承诺的解决方案或拒绝,并将结果放入 PromiseInspection 对象,然后成为承诺的解析值。



然后您将使用此实现;

  Promise.settle([...])。then(function(results){
results.forEach(function(pi,index){
if(pi.isFulfilled()){
console.log(p [+ index +]被满足value =,pi.value());
} else {
console.log(p [+ index +]被拒绝,原因=,pi.reason());
}
});
}) ;






FYI,我写了另一个版本的 .settle 我自己,我调用 .settleVal(),我经常发现,当你不需要实际的拒绝原因,你只是想知道一个给定的阵列槽是否被拒绝。在此版本中,您将传递一个默认值,该值应替代任何被拒绝的承诺。然后,您只需获得一个平坦的值返回值,并将其设置为默认值(被拒绝)。例如,您经常可以选择 rejectVal null 0 {} ,使结果更容易处理。以下是功能:

  //解决所有承诺。对于拒绝的承诺,返回一个特定的rejectVal,它是
//可以与您的成功返回值区分开(通常为null或0或或{})
Promise.settleVal = function(rejectVal,promises){
return Promise.all(promises.map(function(p)){
//确保任何值或外部承诺都包含在promise中
返回Promise.resolve(p).then(null ,函数(err){
//而不是拒绝,只返回rejectVal(通常为null或0或或{})
return rejectVal;
});
}));
};

然后,您可以这样使用:

  Promise.settleVal(null,[...])。then(function(results){
results.forEach(function(pi,index){
if(pi!== null){
console.log(p [+ index +]被满足value =,pi);
}
});
});

这不是整个替换 .settle()因为有时你可能想知道它被拒绝的实际原因,或者你不能轻易地将被拒绝的值与未拒绝的值区分开来。但是,我发现超过90%的时间,这比较简单。






这是我最新的简化 .settle()在返回数组中留下 instanceof Error 作为区分解析值和拒绝错误的方法:

  //解决所有承诺。对于被拒绝的承诺,在返回的数组中留下一个Error对象
Promise.settleVal = function(promises){
return Promise.all(promises.map(function(p)){
// make确保任何价值或外国承诺都包裹在承诺中
return Promise.resolve(p).catch(function(err){
let returnVal = err;
//而不是拒绝,离开数组中的Error对象作为解析值
//确保错误包装在Error对象中(如果还没有错误对象)
if(!(err instanceof Error)){
returnVal = new Error();
returnVal.data = err;
}
return returnVal;
});
}));
};

然后,您可以这样使用:

  Promise.settleVal(null,[...])。then(function(results){
results.forEach(function(item,index){
if(item instanceof Error){
console.log(p [+ index +] reject with error =,item);
} else {
console.log( p [+ index +]满足value =,item);
}
});
});

这可以完全替代 .settle()对于所有情况,只要一个 instanceof Error 从来没有解决您的承诺的价值(这真的不应该是)。


Let's say I have a Promise.all() that handles two promises. If one promise produces an error, but the other resolves, I would like to be able to handle the errors based on the situation after the Promise.all() has settled.

ES6 Promises are missing the settle method, I'm assuming for a good reason. But I can't help but think that the .settle() method would make this problem a lot easier for me.

Am I going about this the wrong way or is extending the ES6 Promises with a settle method the right thing to do here?

An example of how I am thinking of using .settle():

Promise.all([Action1,Action2])
.settle(function(arrayOfSettledValues) 
    //if 1 failed but not 2, handle
    //if 2 failed but not 1, handle
    //etc....
)

解决方案

Am I going about this the wrong way or is extending the ES6 Promises with a settle method the right thing to do here?

You can't directly use Promise.all() to generate .settle() type behavior that gets you all the results whether any reject or not because Promise.all() is "fast-fail" and returns as soon as the first promise rejects and it only returns that reject reason, none of the other results.

So, something different is needed. Often times, the simplest way to solve that problem is by just adding a .then() handler to whatever operation creates your array of promises such that it catches any rejects and turns them into fulfilled promises with some specific value that you can test for. But, that type of solution is implementation dependent as it depends upon exactly what type of value you are returning so that isn't entirely generic.

If you want a generic solution, then something like .settle() is quite useful.

You can't use the structure:

Promise.all([...]).settle(...).then(...);

Because Promise.all() rejects when the first promise you pass it rejects and it returns only that rejection. The .settle() logic works like:

Promise.settle([...]).then(...);

And, if you're interested, here's a fairly simple implementation of Promise.settle():

// ES6 version of settle
Promise.settle = function(promises) {
    function PromiseInspection(fulfilled, val) {
        return {
            isFulfilled: function() {
                return fulfilled;
            }, isRejected: function() {
                return !fulfilled;
            }, isPending: function() {
                // PromiseInspection objects created here are never pending
                return false;
            }, value: function() {
                if (!fulfilled) {
                    throw new Error("Can't call .value() on a promise that is not fulfilled");
                }
                return val;
            }, reason: function() {
                if (fulfilled) {
                    throw new Error("Can't call .reason() on a promise that is fulfilled");
                }
                return val;
            }
        };
    }

    return Promise.all(promises.map(function(p) {
        // make sure any values are wrapped in a promise
        return Promise.resolve(p).then(function(val) {
            return new PromiseInspection(true, val);
        }, function(err) {
            return new PromiseInspection(false, err);
        });
    }));
}

In this implementation, Promise.settle() will always resolve (never reject) and it resolves with an array of PromiseInspection objects which allows you to test each individual result to see whether it resolved or rejected and what was the value or reason for each. It works by attaching a .then() handler to each promise passed in that handles either the resolve or reject from that promise and puts the result into a PromiseInspection object which then becomes the resolved value of the promise.

You would then use this implementation like this;

Promise.settle([...]).then(function(results) {
    results.forEach(function(pi, index) {
        if (pi.isFulfilled()) {
            console.log("p[" + index + "] is fulfilled with value = ", pi.value());
        } else {
            console.log("p[" + index + "] is rejected with reasons = ", pi.reason());
        }
    });
});


FYI, I've written another version of .settle myself that I call .settleVal() and I often find it easier to use when you don't need the actual reject reason, you just want to know if a given array slot was rejected or not. In this version, you pass in a default value that should be substituted for any rejected promise. Then, you just get a flat array of values returned and any that are set to the default value where rejected. For example, you can often pick a rejectVal of null or 0 or "" or {} and it makes the results easier to deal with. Here's the function:

// settle all promises.  For rejected promises, return a specific rejectVal that is
// distinguishable from your successful return values (often null or 0 or "" or {})
Promise.settleVal = function(rejectVal, promises) {
    return Promise.all(promises.map(function(p) {
        // make sure any values or foreign promises are wrapped in a promise
        return Promise.resolve(p).then(null, function(err) {
            // instead of rejection, just return the rejectVal (often null or 0 or "" or {})
            return rejectVal;
        });
    }));
};

And, then you use it like this:

Promise.settleVal(null, [...]).then(function(results) {
    results.forEach(function(pi, index) {
        if (pi !== null) {
            console.log("p[" + index + "] is fulfilled with value = ", pi);
        }
    });
});

This isn't an entire replacement for .settle() because sometimes you may want to know the actual reason it was rejected or you can't easily distinguish a rejected value from a non-rejected value. But, I find that more than 90% of the time, this is simpler to use.


Here's my latest simplification for .settle() that leaves an instanceof Error in the return array as the means of distinguishing between resolved values and rejected errors:

// settle all promises.  For rejected promises, leave an Error object in the returned array
Promise.settleVal = function(promises) {
    return Promise.all(promises.map(function(p) {
        // make sure any values or foreign promises are wrapped in a promise
        return Promise.resolve(p).catch(function(err) {
            let returnVal = err;
            // instead of rejection, leave the Error object in the array as the resolved value
            // make sure the err is wrapped in an Error object if not already an Error object
            if (!(err instanceof Error)) {
                returnVal = new Error();
                returnVal.data = err;
            }
            return returnVal;
        });
    }));
};

And, then you use it like this:

Promise.settleVal(null, [...]).then(function(results) {
    results.forEach(function(item, index) {
        if (item instanceof Error) {
            console.log("p[" + index + "] rejected with error = ", item);
        } else {
            console.log("p[" + index + "] fulfilled with value = ", item);
        }
    });
});

This can be a complete replacement for .settle() for all cases as long as an instanceof Error is never a resolved value of your promises (which it really shouldn't be).

这篇关于ES6 Promise.all()错误句柄 - 需要.settle()吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆