我是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();