let stop = false;
function functionA() {
return Promise.reject();
}
const processMe = function(label) {
if (stop) {
console.log("processMe stop");
return;
}
functionA()
.then(function() {
console.log(`${label} then handler`);
})
.catch(function(err) {
stop = true;
console.log(`${label} catch handler`);
});
};
console.log("Starting loop");
for (let n = 0; n < 10; ++n) {
if (stop) {
break;
}
setTimeout(function(){
processMe(n)
}, n * 1000);
}
console.log("Loop complete");
以上代码并非100%完成。如果它像现在那样运行,则可以正常工作,问题在于当functionA执行其中调用Promise.reject()的Worker时,运行此代码将导致:
Starting loop
Loop complete
0 catch handler
1 catch handler
2 catch handler
3 catch handler
4 catch handler
...
因此使用“停止”标志将无效。
答案 0 :(得分:1)
Chrome上的行为与其他任何符合规范的JavaScript引擎相同:如果functionA
中processMe
的承诺在该循环中始终被拒绝,则catch
处理程序将循环完成后,每次添加到其中的代码都将称为 。保证回调将异步发生。¹如果functionA
自身引发异常,因为它是同步的(假定它不在async
函数中),则该异常将同步终止循环。但不是诺言拒绝。
示例:
function functionA() {
return Promise.reject();
}
const processMe = function(label) {
functionA()
.then(function() {
console.log(`${label} then handler`);
})
.catch(function(err) {
console.log(`${label} catch handler`);
});
};
console.log("Starting loop");
for (let n = 0; n < 10; ++n) {
processMe(n);
}
console.log("Loop complete");
输出为:
Starting loop Loop complete 0 catch handler 1 catch handler 2 catch handler
...等等,在Chrome,Firefox,Edge和任何符合规范的引擎上。
您在评论中说过,您只希望触发一个catch
。为此,可以:
Promise.all
,并让processMe
返回承诺链(而不使用catch
)。然后在循环所在的位置使用catch
。同时进行-请注意,我给了最后一个失败的机会为50%,因此请运行几次以查看成功和错误:
function functionA(n) {
console.log(`functionA starting ${n}`)
return new Promise((resolve, reject) => {
setTimeout(() => {
if (n === 9 && Math.random() < 0.5) {
reject(new Error(`error processing ${n}`));
} else {
resolve();
}
}, Math.random() * 1000);
});
}
const processMe = function(n) {
return functionA(n)
.then(result => {
console.log(`${n} then handler`);
return result;
});
};
console.log("Starting loop");
const promises = [];
for (let n = 0; n < 10; ++n) {
promises.push(processMe(n));
}
Promise.all(promises)
.then(() => {
console.log("All promises completed");
})
.catch(error => {
console.log(`Got rejection: ${error.message}`);
});
.as-console-wrapper {
max-height: 100% !important;
}
连续(第2个,共1个)(最后一个失败的几率为50%)
function functionA(n) {
console.log(`functionA starting ${n}`)
return new Promise((resolve, reject) => {
setTimeout(() => {
if (n === 9 && Math.random() < 0.5) {
reject(new Error(`error processing ${n}`));
} else {
resolve();
}
}, Math.random() * 200);
});
}
const processMe = function(n) {
return functionA(n)
.then(result => {
console.log(`${n} then handler`);
return result;
});
};
console.log("Starting loop");
let promise = Promise.resolve();
for (let n = 0; n < 10; ++n) {
promise = promise.then(() => processMe(n));
}
promise
.then(() => {
console.log("All promises completed");
})
.catch(error => {
console.log(`Got rejection: ${error.message}`);
});
.as-console-wrapper {
max-height: 100% !important;
}
串联(第2个,共2个):如果循环正在遍历数组,并且您想串联进行,则有一个成语,即“ promise reduce
”成语。看起来像这样(上一次失败的几率是50%):
function functionA(n) {
console.log(`functionA starting ${n}`)
return new Promise((resolve, reject) => {
setTimeout(() => {
if (n === 9 && Math.random() < 0.5) {
reject(new Error(`error processing ${n}`));
} else {
resolve();
}
}, Math.random() * 200);
});
}
const processMe = function(n) {
return functionA(n)
.then(result => {
console.log(`${n} then handler`);
return result;
});
};
console.log("Starting loop");
const theArray = [0,1,2,3,4,5,6,7,8,9];
const promise = theArray.reduce((p, n) => {
return p.then(() => processMe(n));
}, Promise.resolve());
promise
.then(() => {
console.log("All promises completed");
})
.catch(error => {
console.log(`Got rejection: ${error.message}`);
});
.as-console-wrapper {
max-height: 100% !important;
}
¹承诺完成次数为queued to the PromiseJobs queue。由于JavaScript具有从运行到完成的语义,因此直到当前作业(运行循环)完成之前,才能运行PromiseJobs队列中的作业。