我正在通过雄辩的javascript并且必须实现promise.all。这是我的解决方案。
function all(promises) {
return new Promise(function(success, fail) {
var results = [];
var failed = false;
promises.forEach(function(promise) {
promise.then(function(result) {
results.push(result);
}, function (error) {
failed = true;
fail(error);
});
});
if (!failed)
success(results);
});
}
以下是我正在进行的测试。
// Test code.
all([]).then(function(array) {
console.log("This should be []:", array);
});
function soon(val) {
return new Promise(function(success) {
setTimeout(function() { success(val); },
Math.random() * 500);
});
}
all([soon(1), soon(2), soon(3)]).then(function(array) {
console.log("This should be [1, 2, 3]:", array);
});
function fail() {
return new Promise(function(success, fail) {
fail(new Error("boom"));
});
}
all([soon(1), fail(), soon(3)]).then(function(array) {
console.log("We should not get here");
}, function(error) {
if (error.message != "boom")
console.log("Unexpected failure:", error);
});
我的代码显然是错误的,因为它的输出
这应该是[]:[]
这应该是[1,2,3]:[]
我们不应该到这里
第一个是唯一正确的。 实际的解决方案来自我的有缺陷的视图与我写的工作基本相同,可以在这里找到: http://eloquentjavascript.net/code/#17.2
为什么我的代码不起作用?它有什么问题?
答案 0 :(得分:1)
forEach
是同步的,if (!failed)
语句将在Promise解析之前运行。您可以执行以下操作:
function all(promises) {
var results = [],
left = promises.length;
if (!left) {
return Promise.resolve(results)
}
return new Promise((res, rej) => {
promises.forEach((p, i) => {
Promise.resolve(p).then(x => {
results[i] = x
left -= 1
if (left === 0) {
res(results)
}
}, rej)
})
})
}
使用稀疏数组可以保持顺序,例如:
function timeout(n) {
return new Promise((res) => {
setTimeout(() => {
res(n)
}, n)
})
}
var pa = timeout(200)
var pb = timeout(300)
var pc = timeout(100)
// success
all([pa, pb, pc]).then(console.log).catch(console.log) //=> [200, 300, 100]
// error
var pd = Promise.reject('error')
all([pa, pb, pc, pd]).then(console.log).catch(console.log) //=> error
答案 1 :(得分:0)
你到了
if (!failed)
success(results);
这么快。如果所有承诺都完成并且它是最后一个承诺,那么所有承诺都会得到解决。
function all(promises) {
return new Promise(function(success, fail) {
var results = [];
var failed = false;
promises.forEach(function(promise) {
promise.then(function(result) {
results.push(result);
if (results.length == promises.length) {
if (!failed)
success(results);
}
}, function (error) {
failed = true;
fail(error);
});
});
});
}
测试你的功能:
all([soon(1), fail(), soon(3)]).then(function(array) {
console.log("We should not get here");
}, function(error) {
console.log("Fail");
if (error.message != "boom")
console.log("Unexpected failure:", error);
});
但是,它仍然缺乏结果排序。
答案 2 :(得分:0)
正如其他人所说,即使在您的承诺得到解决之前,您的.forEach
也会立即完成。对于.forEach
中的每个承诺,异步计算需要一段随机的时间才能完成。对于此exercise,时间为Math.random() * 5000
。
因此,在每次迭代中,最终结果都是“承诺”,.forEach
继续。这就是你得到一个空数组的原因:[]
。 .forEach
已在您的任何承诺解决之前完成。
您要做的是跟踪解决的每个承诺,一旦您有三个已解决的承诺,您就可以在success
阵列上调用results
处理程序。您可以通过将处理程序之外的闭包变量保存到每个promise的.then()
中来实现此目的。当每个promise完成时,您可以增加该变量。在我的解决方案中,我将此变量命名为count
:
function all(promises) {
return new Promise(function(success, fail) {
if (promises.length === 0) {
return success([]);
}
const results = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then(val => {
results[i] = val;
count++;
if (count === promises.length) {
return success(results);
}
}).catch(err => fail(err));
}
});
}