假设我有一个Promise.all()
处理两个诺言的。如果一个承诺产生了错误,而另一个承诺解决了,我希望能够根据Promise.all()
解决后的情况来处理错误。
我认为ES6 Promises缺少解决方法,这是有充分理由的。但是我不禁认为该.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()
“快速失败”而拒绝,并在第一个promise拒绝后立即返回,并且仅返回该拒绝原因,而没有其他结果。
因此,需要一些不同的东西。通常,解决该问题的最简单方法是,仅在.then()
创建诺言数组的任何操作中添加处理程序,以便它捕获所有否决项并将它们转变为具有可测试的特定值的诺言。但是,这种解决方案的类型取决于实现,因为它完全取决于您要返回的值的类型,因此这不是完全通用的。
如果您想要一个通用的解决方案,那么类似的东西.settle()
将非常有用。
您不能使用以下结构:
Promise.all([...]).settle(...).then(...);
注意(于2019年添加):似乎Promise标准工作已被Promise.allSettled()
选为“类似定居点”行为的标准实现。您可以在此答案的末尾看到更多信息。
因为Promise.all()
当您通过第一个诺言时会拒绝,所以它会拒绝,并且仅返回该拒绝。该.settle()
逻辑工作方式:
Promise.settle([...]).then(...);
而且,如果您有兴趣,这里是一个相当简单的实现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);
});
}));
}
在此实现中,Promise.settle()
将始终解析(从不拒绝),并使用PromiseInspection
对象数组进行解析,该对象数组允许您测试每个单独的结果,以查看它是已解决还是被拒绝以及每个值或原因是什么。它通过.then()
为传入的每个promise
附加一个处理程序来处理该promise的拒绝或拒绝,并将结果放入PromiseInspection
对象,该对象随后成为promise的resolved值。
然后,您将使用这种实现方式;
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());
}
});
});
仅供参考,我写了另一个.settle
我自己的版本,.settleVal()
当您不需要实际的拒绝原因时,您只想知道给定的阵列插槽是否被拒绝,我经常发现它更易于使用。在此版本中,您传入一个默认值,该默认值应替代任何拒绝的承诺。然后,您只获得返回值的平面数组,并拒绝所有设置为默认值的值。例如,你经常可以挑选rejectVal
的null
或0
或""
或{}
它使结果更容易对付。功能如下:
// 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;
});
}));
};
然后,您可以像这样使用它:
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
在返回数组中保留了一个区分分辨值和拒绝错误的方法:
// 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;
});
}));
};
然后,您可以像这样使用它:
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
它永远不是您的诺言的可解决的价值(实际上是不应该的),这可以完全替代所有情况。
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);
}
}
用法如下:
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年晚些时候)。
假设我有一个处理两个promise的Promise.all()。如果一个promise产生一个错误,但另一个解决了,我希望能够根据Promise.all()解决后的情况处理这些错误。 我认为ES6promise缺少结算方法是有充分理由的。但是我忍不住想,方法会让我更容易解决这个问题。 我是不是走错了路,还是用解决方法扩展ES6promise是正确的做法? 关于我如何使用的示例:
问题内容: 对于我因此遇到的所有Dockerfile(虽然数量不多),它们所有人都使用了子句作为现有映像的基础,即使它是。 这个条款是必需的吗?有没有子句的Dockerfile是否可能?这样创建的容器可以执行任何操作吗? 编辑 我读 没有FROM指令的Dockerfile没有父映像,称为基本映像。 https://docs.docker.com/glossary/?term=parent%20im
问题内容: 两列的大小写条件是相同的。在下面的语句中,我两次使用了此条件,但对于不同的列,是否还有其他方法不重复两次条件? 问题答案: thepirat000答案的变体: 查找表是在CTE中创建的,并根据需要为多列进行引用。 更新: 由于某些莫名其妙的原因,表变量现在被赋予了主键。如果有人可以真正解释一下它将如何提高性能,那么我很想听听它。从执行计划来看并不明显。
我刚刚注意到javadoc状态(强调为我的): 返回声明中包含的此枚举常量的名称。该方法可能被重写,尽管它通常不是必需的或不需要的。当存在更“程序员友好”的字符串窗体时,枚举类型应重写此方法。 默认情况下,和返回相同的内容,因此即使被重写,仍然可以通过方法访问枚举的名称。 编辑:供参考,的javadoc(强调与原文相同): 返回此枚举常量的名称,与在其枚举声明中声明的名称完全相同。大多数程序员应该
问题内容: 以下语句在我的数据库中有效: 但这不是: 我得到了错误: 错误:“ my_table.column_a”列必须出现在GROUP BY子句中或在聚合函数中使用 有用的注释:该线程:SQL子句“ GROUP BY1”是什么意思? 讨论“ ”的含义。 更新: 我感到困惑的原因是因为我经常看到如下情况: 那里是 没有 说法。是否总是需要跟着 ?在这种情况下,该语句是否隐含? 问题答案: 这个错
问题内容: 我只是在浏览一个论坛,有人问他们在网上找到的PHP文件。在代码中有几个这样的地方: 我一直认为,如果条件为真,则需要用括号括起来。还有其他选择吗,例如您是否不在同一行? 还有另一行是这样的: 我的本能是说这行不通,但是我也不知道它是否是过时的PHP文件并且它曾经可以工作? 问题答案: 您可以执行以下其他语句: 然后您还可以编写if-else的替代语法: 使用备用语法,您也可以退出解析模