This example (repl.it)(来自this answer)在我看来,它遵循了有关承诺的所有规则。但是运行它会记录有关未处理的诺言拒绝的异常以及相关的控制台消息。 (在FF,Chrome和Node v10中也会发生这种情况。)
try / catch块显然在那里并包装了被拒绝的承诺,那么怎么回事以及如何解决呢?
async function example() {
const start = Date.now()
let i = 0
function res(n) {
const id = ++i
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`res #${id} called after ${n} milliseconds`, Date.now() - start)
}, n)
})
}
function rej(n) {
const id = ++i
return new Promise((resolve, reject) => {
setTimeout(() => {
reject()
console.log(`rej #${id} called after ${n} milliseconds`, Date.now() - start)
}, n)
})
}
try {
const delay1 = res(3000)
const delay2 = res(2000)
const delay3 = rej(1000)
const data1 = await delay1
const data2 = await delay2
const data3 = await delay3
} catch (error) {
console.log(`await finished`, Date.now() - start)
}
}
example()
答案 0 :(得分:7)
问题在于,在rej
调用被拒绝的那一点上,解释器尚未到达await
符合rej
创建的诺言的行,因此被拒绝的Promise就是被拒绝的Promise,而不是当前线程正在await
正在
try {
const delay1 = res(3000)
const delay2 = res(2000)
const delay3 = rej(1000)
const data1 = await delay1
// The interpreter is paused on the line above when `rej` rejects
const data2 = await delay2
const data3 = await delay3
因此,其行为与在没有catch
处理程序的情况下声明被拒绝的Promise相同。 (如果Promise抛出的错误在Promise拒绝的地方被async
编辑,则会在await
函数中捕获错误-否则,只会导致处于未处理的承诺拒绝中。)
我建议您在await
的同一时刻声明承诺:
const data1 = await res(3000)
(注意:以上方法的计时与原始代码不同)
或对所有Promise使用await Promise.all
,这意味着解释器当前Promise
正在await
处将尽快抛出(从而进入catch
块) 一个承诺被拒绝:
const [data1, data2, data3] = await Promise.all([
res(3000),
res(2000),
rej(1000)
]);
async function example() {
const start = Date.now()
let i = 0
function res(n) {
const id = ++i
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`res #${id} called after ${n} milliseconds`, Date.now() - start)
}, n)
})
}
function rej(n) {
const id = ++i
return new Promise((resolve, reject) => {
setTimeout(() => {
reject()
console.log(`rej #${id} called after ${n} milliseconds`, Date.now() - start)
}, n)
})
}
try {
const [data1, data2, data3] = await Promise.all([
res(3000),
res(2000),
rej(1000),
]);
} catch (error) {
console.log(`error caught: await finished`, Date.now() - start)
}
}
example()
要在三个Promise进行时进行其他工作,并从这些Promise以及主线程中捕获错误,请将第四项传递给Promise.all
,IIFE做您想做的其他工作:
async function example() {
const start = Date.now()
let i = 0
function res(n) {
const id = ++i
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`res #${id} called after ${n} milliseconds`, Date.now() - start)
}, n)
})
}
function rej(n) {
const id = ++i
return new Promise((resolve, reject) => {
setTimeout(() => {
reject()
console.log(`rej #${id} called after ${n} milliseconds`, Date.now() - start)
}, n)
})
}
try {
const [data1, data2, data3] = await Promise.all([
res(3000),
res(2000),
rej(1000),
(() => {
console.log('doing work...');
})()
]);
} catch (error) {
console.log(`error caught: await finished`, Date.now() - start)
}
}
example()