Javascript异步函数中的Await关键字并不是在等待承诺按顺序完成



我是Javascript的新手,正在尝试学习promise和async/await概念。我创建了三个承诺,如下所示。

const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000)
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000)
});

我创建了一个异步函数,它使用await按顺序执行多个promise,如下所示。


async function example() {

const result1 = await promise1;
const result2 = await promise2;
const result3 = await promise3;
console.log(result1);
console.log(result2);
console.log(result3);
}
example();

浏览器控制台中的输出为-

promise1
promise3
promise2
1
2
3

我不明白为什么在我的输出中promise3在promise2之前,因为在异步函数示例中的等待语句序列中,promise2在promise3之前?根据我的说法,输出应该如下-

promise1
promise2
promise3
1
2
3

如果我遗漏了什么或有什么错误,请纠正我。

const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});

构造promise时,其内部的代码会立即运行。因此,一旦这条线完成,计时器就会关闭并运行。您的代码提前创建了其中的3个promise,这意味着它提前启动所有3个定时器。

稍后,当您await承诺时,这不会改变计时器正在做的事情。它只是让您的async函数知道它们何时完成。因此,在后台,计时器将开始关闭,将事情注销,并解决相应的承诺。即使没有什么等待承诺,这种情况也可能发生。1000ms的超时将首先响起,3秒后是4000ms的超时,1秒后是5000ms的

如果您希望计时器只在到达异步函数的那一行时启动,那么您需要在异步函数的这一行执行setTimeouts。例如:

async function example() {
const result1 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000);
});
const result2 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000);
});
const result3 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000);
});
console.log(result1);
console.log(result2);
console.log(result3);
}

简而言之,这是因为您首先创建了这三个promise,在创建这三个Promise的过程中,您还启动了三个计时器。这三个定时器都启动了,并且都在并行运行。

然后,执行await promise1。但是,该语句与计时器何时调用回调完全无关。他们将完全依靠自己。因此,定时器回调本身会根据每个定时器的预期设置时间创建console.log()输出(与您的await完全无关(。

所以,它是这样发生的,因为你的第一个创建了所有三个承诺和定时器,然后,只有在那时,你才会做await。这里需要理解的一件重要的事情是;承诺不会兑现;。它们本身并不是异步操作。一旦执行了new Promise(),它就会调用promise executor函数,并且启动其中的异步操作。从那时起,promise所做的就是监视异步操作,然后在异步操作完成时通知观察者。

如果添加每个计时器启动时的日志记录,您可以看到更多关于事情顺序的详细信息,这将显示所有三个计时器最初都是并行启动和运行的,并且可以在代码中完全独立于await语句调用它们的计时器回调:

const promise1 = new Promise((resolve, reject) => {
console.log("starting timer 1");
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
const promise2 = new Promise((resolve, reject) => {
console.log("starting timer 2");
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000)
});
const promise3 = new Promise((resolve, reject) => {
console.log("starting timer 3");
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000)
});
async function example() {
const result1 = await promise1;
const result2 = await promise2;
const result3 = await promise3;
console.log(result1);
console.log(result2);
console.log(result3);
}
example();

如果你改变了代码的结构,让你等待的函数真正创建和启动计时器,那么你就不会启动第二个计时器,直到第一个计时器启动后,你就会有顺序计时器。

因此,如果你这样做,你的预期输出就会发生:

function runTimer1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
}
function runTimer2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise2");
resolve("2");
}, 5000)
});
}
function runTimer3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise3");
resolve("3");
}, 4000)
});
}
async function example() {
const result1 = await runTimer1();
const result2 = await runTimer2();
const result3 = await runTimer3();
console.log(result1);
console.log(result2);
console.log(result3);
}
example();

这是因为您在异步函数之外创建Promises而不需要等待Promise内部的回调是syncrounos。您可以一个接一个地运行3个setTimeout。示例:

const x = new Promise(resolve => console.log(1))
console.log(2)

这会注销1,2,而不是setTimeout的异步回调:

setTimeout(() => console.log(1));
console.log(2)

这会注销2.1。

因此,如果你想要正确的行为,你必须在等待承诺时创建承诺,这是常见的做法:

function makePromise(time, number) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise", number);
resolve(number);
}, time);
});
}

async function example() {
const result1 = await makePromise(1000, 1);
const result2 = await makePromise(5000, 2);
const result3 = await makePromise(4000, 3);
console.log(result1);
console.log(result2);
console.log(result3);
}
example();

最新更新