Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >ES6 Promise.all()错误句柄-需要.settle()吗?

ES6 Promise.all()错误句柄-需要.settle()吗?
EN

Stack Overflow用户
提问于 2016-04-13 09:13:48
回答 1查看 9.2K关注 0票数 10

假设我有一个处理两个承诺的Promise.all()。如果一个承诺产生错误,但另一个承诺解决了错误,我希望能够在Promise.all()解决后根据情况处理错误。

ES6承诺错过了结算方法,我认为这是有充分理由的。但我不禁认为,.settle()方法会使这个问题对我来说容易得多。

我是走错路了,还是用解决方法扩展ES6承诺是正确的呢?

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.all([Action1,Action2])
.settle(function(arrayOfSettledValues) 
    //if 1 failed but not 2, handle
    //if 2 failed but not 1, handle
    //etc....
)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-13 09:24:45

我是走错路了,还是用解决方法扩展ES6承诺是正确的呢?

您不能直接使用Promise.all()来生成.settle()类型行为,因为Promise.all()是“快速失败”,并且在第一个承诺拒绝时立即返回,并且它只返回拒绝原因,其他结果都不返回,从而获得所有结果--不管是否拒绝。

所以,我们需要一些不同的东西。通常情况下,解决该问题的最简单方法是向任何创建承诺数组的操作中添加一个.then()处理程序,这样就可以捕获任何拒绝,并将它们转化为具有特定值的承诺,您可以对其进行测试。但是,这种类型的解决方案依赖于实现,因为它取决于您返回的值类型,因此这并不是完全通用的。

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

您不能使用该结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.all([...]).settle(...).then(...);

备注(添加于2019年):看来承诺标准努力选择了 Promise.allSettled() 作为“类结算”行为的标准实现。在这个答案的末尾,您可以看到更多的信息。

因为当您传递第一个承诺时,Promise.all()拒绝它,因此它只返回该拒绝。.settle()逻辑的工作原理如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.settle([...]).then(...);

而且,如果您感兴趣,下面是Promise.settle()的一个相当简单的实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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);
        });
    }));
}

在此实现中,Promise.settle()将始终解析(永不拒绝),并使用一个PromiseInspection对象数组进行解析,该数组允许您测试每个单独的结果,以查看其解析或拒绝,以及每个结果的值或原因。它的工作方式是将一个.then()处理程序附加到传递给它的每个承诺,这些承诺处理该承诺的决定或拒绝,并将结果放入一个PromiseInspection对象中,然后该对象成为承诺的解析值。

然后,您将像这样使用这个实现;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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,我自己编写了另一个版本的.settle,我称之为.settleVal(),当您不需要实际的拒绝原因时,我发现使用起来更容易,您只是想知道某个给定的数组插槽是否被拒绝。在此版本中,您将传递一个默认值,该默认值应替代任何拒绝的承诺。然后,您只会得到一个返回值的平面数组,并将其设置为默认值,其中任何值都是被拒绝的。例如,您通常可以选择一个rejectVal of null0""{},这样就可以更容易地处理结果。以下是功能:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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;
        });
    }));
};

然后,你就这样用它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.settleVal(null, [...]).then(function(results) {
    results.forEach(function(pi, index) {
        if (pi !== null) {
            console.log("p[" + index + "] is fulfilled with value = ", pi);
        }
    });
});

这并不是.settle()的全部替代品,因为有时您可能想知道它被拒绝的实际原因,或者很难区分被拒绝的值和未拒绝的值。但是,我发现90%以上的时间,这是比较简单的使用。

下面是我对.settle()的最新简化,它将返回数组中的instanceof Error作为区分已解析值和拒绝错误的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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;
        });
    }));
};

然后,你就这样用它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
        }
    });
});

对于所有情况,这都可以完全替代.settle(),只要instanceof Error永远不是您的承诺的解析值(它确实不应该是)。

承诺标准努力

到2019年,.allSettled()似乎正在成为这类行为的标准。还有,这是一个多填区:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (!Promise.allSettled) {
    Promise.allSettled = function(promises) {
        let wrappedPromises = Array.from(promises).map(p => 
             this.resolve(p).then(
                 val => ({ state: 'fulfilled', value: val }),
                 err => ({ state: 'rejected', reason: err })
             )
        );
        return this.all(wrappedPromises);
    }
}

用法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let promises = [...];    // some array of promises, some of which may reject
Promise.allSettled(promises).then(results => {
    for (let r of results) {
        if (r.state === 'fulfilled') {
            console.log('fulfilled:', r.val);
        } else {
            console.log('rejected:', r.err);
        }
    }
});

请注意,Promise.allSettled()本身总是解决问题,从不拒绝,尽管后续的.then()处理程序可能会抛出或返回被拒绝的承诺,从而使整个链拒绝。

截至2019年6月,这还没有在目前的桌面Chrome浏览器,但计划在即将发布(例如,在2019年晚些时候)。

票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36605253

复制
相关文章
现代脚本的加载
原文地址: Modern Script Loading, 文章作者是Preact作者Jason Miller
_sx_
2019/08/07
8700
Js脚本的异步加载
在浏览器中网页加载中 javascript 的 加载 和 执行会默认阻塞 DOM 的加载和页面的渲染。 因此,在编写代码的时候我们往往将 script 标签放到 body 的最后面。 当然,也可以通过异步创建 script 标签的方式来实现 js的异步加载。
epoos
2022/06/06
9.1K0
Js脚本的异步加载
无阻塞加载脚本
通常加载页面的时候,对于组件是并行下载的,现代大部分浏览器对于Js同样也是支持并行下载,但是在脚本下载、解析并执行完毕之前,不会开始下载任何其他内容。
菜的黑人牙膏
2019/01/21
4360
gdb加载python脚本的方法
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/details/76733977
血狼debugeeker
2018/09/20
2K0
智能图像签名生成脚本
https://cloud.tencent.com/document/product/867/17719
杜志强
2019/03/21
9300
Cycript 小知识:加载自己的脚本
Cycript是一个理解Objective-C语法的javascript解释器,这意味着我们能够在一个命令中用Objective-C或者javascript,甚至2者兼用。它能够挂钩正在运行的进程,能够在运行时修改应用的很多东西。
公众号iOS逆向
2022/08/22
6000
安装java脚本
卸载掉现有的JAVA版本的话,可以使用 rpm -qa | grep java 和 rpm -e xxx --nodeps进行卸载
summerking
2022/10/27
5040
java 脚本引擎
本文节选自《Netkiller Java 手札》 第 18 章 java 脚本引擎 目录 18.1. Maven 18.2. Helloworld 18.3. 运行脚本文件 18.4. 变量传递 18.5. 全局变量与局部变量定义 18.6. 调用脚本中的函数或方法 18.7. 脚本编译 什么是脚本引擎,脚本引擎是指在程序运行期间嵌入另一种脚本语言,并与其交互,产生最终运行结果 脚本引擎存在的意义是什么?脚本引擎可以改变编译语言的内部运行逻辑,弥补编译语言的不足,使编译语言具备动态语言的一部分特性。 是否有
netkiller old
2018/03/05
1.8K0
JavaScript 动态加载脚本和样式
3大点: 1.元素位置 2.动态脚本 3.动态样式 一.元素位置 getBoundingClientRect()。这个方法返回一个矩形对象,包含四个属性:left、top、right和bottom。分别表示元素各边与页面上边和左边的距离。 var box = document.getElementById('box');//获取元素 alert(box.getBoundingClientRect().top);//元素上边距离页面上边的距离 alert(box.getBoundingClientRect()
汤高
2018/01/11
1.4K0
Java动态脚本
诸如此类的需求若采用硬编码实现,则迭代成本相当高,每次改动都需要进行开发、测试、部署。同时业务规则的频繁变更会导致代码的开发和维护成本大大提高。
ruochen
2021/11/22
1K0
Java中ImageIcon的路径问题
这行代码执行时在project目录下查找名为logo.gif的文件,结果当然是找不到。
緣來
2020/01/02
2.9K0
异步加载脚本保持执行顺序
首先是外部脚本和行内脚本,对于异步加载的脚本,会导致竞争状态,使得出现未定义的错。
菜的黑人牙膏
2019/01/21
1.8K0
Quick-Task 动态脚本支持框架之Groovy脚本加载执行
上一篇简答说了如何判断有任务动态添加、删除或更新,归于一点就是监听文件的变化,判断目录下的Groovy文件是否有新增删除和改变,从而判定是否有任务的变更;
一灰灰blog
2018/08/07
1.2K0
Quick-Task 动态脚本支持框架之Groovy脚本加载执行
用shell脚本猜大小
创建shell脚本环境 vim guess 极简猜大小 echo $1 if [ $1 -gt 12 ]; then echo "猜大了" elif [ $1 -lt 12 ]; then echo "猜小了" else echo "猜对了" break fi 用while语句 猜大小 while true; do echo "请输入一个数字" read aa; if [ $aa -gt 12 ]; then echo "
Maynor
2021/04/09
2740
用Python写Shell脚本
os.system函数与系统编程中的exec族函数调用一致,创建出子进程后代码段由外部程序替换,不会返回外部程序运行结果。
菜菜cc
2022/11/15
1.5K0
Java动态脚本运用
一般的需求可使用上述动态脚本实现,如果遇到业务规则更为复杂、规模更大、对功能和性能有更高要求的需求时,可考虑更为专业的规则引擎和计算/表达式引擎。
花落花相惜
2021/12/15
1.3K0
JAVA调用Shell脚本
在实际项目中,JAVA有时候需要调用C写出来的东西,除了JNI以外,我认为一种比较好的方法是JAVA调用Shell。先把C写出来的make成可执行文件,然后再写一个shell脚本执行该可执行文件,最后是JAVA调用该shell脚本。 JAVA调用很简单,例子如下: 首先是shell脚本 /users/bmcmsend_linux/server/bin/msend -n @10.26.202.27:1828#mc -a TRKUTIL_EV -v -j /users/bmcmsend_linux/server
Java学习123
2018/05/16
3.1K0
java: ant 脚本示例
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <!--basedir是从build.xml所在的目录为基础算起的--> 4 <project nam
菩提树下的杨过
2018/01/24
8660
180807-Quick-Task 动态脚本支持框架之Groovy脚本加载执行
上一篇简答说了如何判断有任务动态添加、删除或更新,归于一点就是监听文件的变化,判断目录下的Groovy文件是否有新增删除和改变,从而判定是否有任务的变更;
一灰灰blog
2019/05/26
5250
Java基础-脚本引擎
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
cwl_java
2019/11/12
9850

相似问题

SQL server“心跳”检查的最低权限?

33

弹性心跳响应检查TCP错误

12

REST心跳检查服务可用性

11

Api对Api Root执行心跳检查

22

弹性搜索+心跳-是否可以检查java应用程序是否正在运行?

116
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文