Javascript 异步函数中的 Await 关键字未等待承诺按顺序完成
Await keyword in Javascript async function is not waiting for promises to complete in sequential order
我是 Javascript 的新手,正在尝试学习 promises 和 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 进行多个承诺,如下所示。
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 之前,因为在异步函数示例中的 await 语句序列中,promise2 出现在 promise3 之前?根据我的说法,输出应该如下所示 -
promise1
promise2
promise3
1
2
3
如有遗漏或错误,请指正。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
当您构造一个承诺时,其中的代码立即运行。因此,一旦完成此行,计时器就会关闭并且 运行。您的代码预先创建了其中的 3 个承诺,这意味着它预先启动了所有 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 内部的回调是 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。
因此,如果您想要正确的行为,则必须在等待它们时创建 Promise,这是常见的做法:
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();
简而言之,这是因为您首先创建了这三个承诺,并且在创建这三个承诺的过程中,您还启动了三个计时器。那三个定时器都启动了,都是运行并行的
然后,你await promise1
。但是,该语句与计时器何时调用其回调完全无关。他们将完全靠自己来做。因此,计时器回调本身会根据每个计时器设置的预期时间创建 console.log()
输出(与您拥有的 await
完全无关)。
所以,之所以会这样,是因为您首先创建了所有三个承诺和计时器,然后才创建了 await
。这里要理解的一件重要事情是“承诺不执行”。它们本身不是异步操作。一旦你执行 new Promise()
,它就会调用 promise 执行器函数,你在那里的异步操作就会启动。从那时起,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();
我是 Javascript 的新手,正在尝试学习 promises 和 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 进行多个承诺,如下所示。
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 之前,因为在异步函数示例中的 await 语句序列中,promise2 出现在 promise3 之前?根据我的说法,输出应该如下所示 -
promise1
promise2
promise3
1
2
3
如有遗漏或错误,请指正。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise1");
resolve("1");
}, 1000)
});
当您构造一个承诺时,其中的代码立即运行。因此,一旦完成此行,计时器就会关闭并且 运行。您的代码预先创建了其中的 3 个承诺,这意味着它预先启动了所有 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 内部的回调是 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。
因此,如果您想要正确的行为,则必须在等待它们时创建 Promise,这是常见的做法:
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();
简而言之,这是因为您首先创建了这三个承诺,并且在创建这三个承诺的过程中,您还启动了三个计时器。那三个定时器都启动了,都是运行并行的
然后,你await promise1
。但是,该语句与计时器何时调用其回调完全无关。他们将完全靠自己来做。因此,计时器回调本身会根据每个计时器设置的预期时间创建 console.log()
输出(与您拥有的 await
完全无关)。
所以,之所以会这样,是因为您首先创建了所有三个承诺和计时器,然后才创建了 await
。这里要理解的一件重要事情是“承诺不执行”。它们本身不是异步操作。一旦你执行 new Promise()
,它就会调用 promise 执行器函数,你在那里的异步操作就会启动。从那时起,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();