我有承诺需要同步的对象。例如,第二个承诺在第一个承诺完成之前不应该工作。如果第一个拒绝第一个必须再次执行。
我已经实施了一些例子。这个很好用。 调用getVal,等待2000ms,返回,i ++,再次调用getVal .....
getVal() {
return new Promise(function(resolve, reject) {
setTimeout(function(){ resolve(19) }, 2000);
});
}
async promiseController(){
for(var i =0;i<5;i++)
{
var _val = await this.getVal()
console.log(_val+'prom');
}
}
但是我需要控制一个promise对象数组。我想要做的是我有一个数据,我把它分成5块。在处理完第一部分(例如:发送到服务器)后,我想要处理第二部分,否则我必须再次处理第一部分。
这是我制作的原型实现
getVal() {
return new Promise(function(resolve, reject) {
setTimeout(function(){ resolve(19) }, 2000);
});
}
async promiseController(){
var proms=[]
for(var i =0;i<5;i++)
{
proms.push(this.getVal())
}
for(var i =0;i<5;i++)
{
var _val = await proms[i]
console.log(_val+'prom');
}
}
此代码中的Promises对象按顺序工作。我如何修复下面的代码,以便它作为第一个例子同步工作。
答案 0 :(得分:3)
async promiseController(){
for(const value of array) {
console.log((await this.getVal(value))+'prom');
}
}
无需过度复杂化。只需在循环中调用await
,它就会等待你想要的东西。
正如另一个答案正确地说 - 承诺代表值而不是操作。对于操作,使用常规函数。
如果你想忽略失败,你可以.catch(() => {})
承诺。如果要重试直到失败 - 您可以重构重试函数并使用:
const retry = fn => (...args) => fn(...args).catch(retry(fn));
答案 1 :(得分:1)
如果您的目标是在第一个承诺解决之前不“执行后续承诺”,那么您需要记住,承诺代表已经在飞行中的异步活动 。一旦承诺存在,就太晚了。
在第一个承诺完成之前,您需要不要调用后续的承诺工厂方法。您的第一个示例通过在前一个承诺完成之前不调用getVal()
来完成此操作。
所以你最终得到的结果是:
delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async promiseController() {
const factories = [];
for (let i = 0; i < 5; ++i) {
factories.push(() => this.getVal());
}
for (const f of factories) {
// keep running this factory until it succeeds
let success = false;
while (!success) {
try {
const promise = f();
const result = await f;
success = true;
console.log(`result = ${result}`);
}
catch (err) {
console.log("promise failed. retrying");
await delay(100);
}
}
}
}
答案 2 :(得分:1)
您可以使用递归,命名函数.then()
var arr = [Promise.resolve("a")
, Promise.resolve("b")
, Promise.resolve("c")];
var i = 0;
var res = [];
function foo() {
// conditional resolved or rejected promise
var n = String(new Date().getTime()).slice(-1);
// if `n` < 5 reject `n` , else resolve `n`
var curr = n < 5;
return curr ? arr[i] : Promise.reject(["rejected", n])
}
var p = (function repeat() {
var promise = foo();
return promise
.then(function(data) {
console.log(data);
res.push(data);
++i;
if (i < arr.length) return repeat()
// return `res` array when all promises complete
else return res
})
.catch(function(err) {
console.log(err);
if (err[0] === "rejected") return repeat()
})
}());
p.then(function(complete) {
console.log("complete:", complete)
});
&#13;
答案 3 :(得分:1)
async
和await
。我相信承诺非常充足。然而,如果您想继续使用C ++编写命令式,那么async
和await
就适合您。
我有承诺需要同步的对象。例如 第一个承诺在第一个承诺完成之前不应该起作用。如果是第一个 拒绝第一个必须再次执行。
让我简单介绍下面的代码。我们有async()
函数,它接受数据和回调(错误优先类型)。至于演示目的,它将尝试在2000ms内使用数据调用回调,但是在1000ms处有超时。所以50-50它将调用带有数据或错误的回调。
所以我们实际上需要它来返回一个承诺,所以我在promisify()
的帮助下宣传它,它需要async()
函数并返回asyncPro()
函数。这实际上与async()
相同,但却返回了一个承诺。因此我们应该在then
阶段使用我们的回调。
接下来是tryNTimes(data,asyncFun,n = 5)
函数,它接受数据,一个promisified异步函数和一个整数,指定在拒绝它之前尝试的次数。它的默认尝试次数为5,但您可以通过传递第三个参数将其设置为任何值。
至于最后一部分,我们flowControl()
在Array.prototype.reduce()
的帮助下完美地完成了我们的承诺。
所以现在我们将所有的承诺一个接一个地链接起来,没有一个会在尝试5次之前失败。
function promisify(fun){
return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}
function async(data, callback){
var dur = Math.floor(Math.random()*2000);
setTimeout(_ => callback(false,data),dur); // may resolve before timeout
setTimeout(_ => callback("error at " + data),1000); // timeout at 1 sec
}
function tryNTimes(data,asyncFun,n = 5){
return new Promise((resolve,reject) => { n === 0 && reject("try out fail at 5 tries: " + data);
asyncFun(data).then(v => resolve("resolved at countdown " + n + ": " + v))
.catch(e => resolve(tryNTimes(data,asyncFun,--n)));
});
}
function flowControl(d,f,tc){
return d.reduce((prom,chunk) => prom.then(v => { console.log(v);
return tryNTimes(chunk,f,tc);
}),Promise.resolve("initial dummy promise"));
}
var data = ["chunk_1", "chunk_2", "chunk_3", "chunk_4", "chunk_5"],
asyncPro = promisify(async); // now our async function returns a promise
flowControl(data,asyncPro).then(v => console.log(v))
.catch(e => console.log(e));
如果您希望更频繁地看到“5次尝试”错误,请降低async()
功能中的超时值。