javascript - 试图定义一个 promise.all
问题描述
我试图通过从本书的练习中创建 Promise.all 方法来了解 Promise 的工作原理: https ://eloquentjavascript.net/11_async.html#i_Ug+Dv9Mmsw
我尝试循环遍历作为方法本身的参数给出的整个数组,使用 .then 用于成功的承诺,其中处理程序的主体将结果推送到我之前在循环之外定义的绑定,对于被拒绝的承诺,我使用 .catch以某种方式将被拒绝的值作为“原因”并拒绝主要的承诺给它一个错误
function Promise_all(promises) {
return new Promise((resolve, reject) => {
if(promises.length == 0) resolve(promises);
let fullArray = [];
for(let i=0; i<promises.length ; i++){
promises[i]
.then(x => fullArray.push(x))
.catch(reason => reject(new Error(reason)));
}
resolve(fullArray);
});
}
我期望该功能执行以下操作:
- 从“承诺”数组中选择一个承诺。
- 通过使用 .then 方法和处理函数来解决承诺(如果成功),该处理函数只是将结果推送到“fullArray”。
- 通过使用 .catch 方法和一个处理函数来解决承诺(如果被拒绝),该处理函数简单地调用将由“Promise_all”返回的主承诺的拒绝处理程序。
- 当循环结束时,只需将成功的 promise 的“fullArray”解析为 promise。
代码根本不像我想象的那样工作,使用本书的测试代码不会返回预期的结果:
Promise_all([]).then(array => {
console.log("This should be []:", array);
});
function soon(val) {
return new Promise(resolve => {
setTimeout(() => resolve(val), Math.random() * 500);
});
}
Promise_all([soon(1), soon(2), soon(3)]).then(array => {
console.log("This should be [1, 2, 3]:", array);
});
Promise_all([soon(1), Promise.reject("X"), soon(3)])
.then(array => {
console.log("We should not get here");
})
.catch(error => {
if (error != "X") {
console.log("Unexpected failure:", error);
}
});
解决方案
正如@Bergi 所说,代码的问题是“.then”和“.catch”回调是异步调用的,因此,在调用“resolve()”时甚至没有填充“fullArray”即使它在循环之外。为了解决这个问题,我只是在最后完成的 Promise 中添加了“resolve()”,为此,我只是添加了一个“counter”绑定,该绑定具有“promises”数组的长度值,并减少了每次在 promise 上调用 ".then" 时为 1,当这个 "counter" 等于 0 时,它调用 "resolve()"。
但这只能解决用 Promise 填充“fullArray”的问题,而不是那些 Promise 按它们被调用的顺序正确排序的问题,为了解决这个问题,我只需使用“i”绑定在数组中枚举它们循环,最终结果是这样的:
function Promise_all(promises) {
return new Promise((resolve, reject) => {
if(promises.length == 0) resolve(promises);
let fullArray = [],
counter = promises.length;
for(let i=0; i< promises.length ; i++){
promises[i]
.then(x => {
fullArray[i] = x;
counter--;
if(counter == 0) resolve(fullArray)})
.catch(reason => reject(new Error(reason)));
}
});
}
推荐阅读
- python - 在 DAG 中添加标签
- json - 如何在 JSON 项中将值分配为具有新值的键?
- c# - 实体类型 EF Migration 中有多个导航
- javascript - 如何在画布上设置鼠标滚轮缩小限制?
- java - 使用 WorkManager 触发推送通知有一些延迟
- layout - 在 iPad 上而不是在 iPhone 上输入 UITextView 时出现 UIButtonBarButton 布局警告
- javascript - Trying to create a dictionary of clothes available in store in javascript
- authentication - AWS Cognito 如何验证我自己的 IdP 颁发的身份令牌?
- php - 将子域重定向到另一个子域并保留页面名称
- azure - 在 Azure 应用服务上运行部署后操作