所有异步函数代码都会在不同的线程中运行吗?
没有。 async 函数、await 和 Promise 不会创建或使用不同的线程。
promise 本身不会使任何事情异步¹,它只是一种观察完成已已经异步的事情(例如您的计时器回调,它使用您环境的计时器子系统,以便稍后调用您的计时器回调)。
async 函数“只是”一种方式(一种非常非常有用的方式) 通过语法而不是通过使用 .then 或附加履行和拒绝处理程序来等待承诺解决.catch 方法。
console.log(res); 这行让我有点惊讶。在 10 秒的超时完成之前打印,但我猜原因是 await 之后的代码没有返回 Promise。
setTimeout 不会返回承诺,对。所以await 不会等待计时器回调发生。请参阅this question's answers,了解如何制作启用承诺的setTimeout 版本。
但是,为什么代码是:console.log('bla bla bla');在两行之前打印:
出于同样的原因:您的async 函数返回一个promise,而您调用async 函数的代码不会等待该promise 得到解决,然后再转到console.log('bla bla bla') 行。
这里的代码既使用了启用承诺的setTimeout 版本,又在执行console.log 之前等待async 函数的承诺解决:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function imaAsyncFunction () {
let res = await delay(800); // 0.8s instead of 10s
console.log("Timer expired");
console.log(res); // undefined, since we haven't set a fulfillment value
console.log("is after");
}
imaAsyncFunction()
.then(() => {
console.log("bla bla bla");
})
.catch(error => {
console.error(error);
});
如果您希望 delay 函数返回一个履行值,我们可以这样做:
function delay(ms, value) {
return new Promise(resolve => setTimeout(() => {
resolve(value);
}, ms));
}
虽然在所有标准环境中(现在),setTimeout 接受一个值传递给它的回调,所以我们可以这样做:
function delay(ms, value) {
return new Promise(resolve => setTimeout(resolve, ms, value));
}
function delay(ms, value) {
return new Promise(resolve => setTimeout(resolve, ms, value));
}
async function imaAsyncFunction () {
let res = await delay(800, 42); // 0.8s instead of 10s
console.log("Timer expired");
console.log(res); // 42
console.log("is after");
}
imaAsyncFunction()
.then(() => {
console.log("bla bla bla");
})
.catch(error => {
console.error(error);
});
在你说过的评论中:
我仍然不明白为什么这两行都没有在 `console.log('bla bla bla'); 之前运行?
这是您的原始代码:
async function imaAsyncFunction () {
console.log('1234');
let res = await setTimeout(()=>{console.log('10 sec');},10000);
console.log(res);
console.log('is After?!?');
}
imaAsyncFunction();
console.log('bla bla bla');
当您运行该代码时,会按顺序发生以下情况:
- 函数
imaAsyncFunction 已创建。
- 对
imaAsyncFunction() 的调用被执行:
- 函数的同步部分运行:
-
console.log('1234'); 被执行
-
setTimeout(()=>{console.log('10 sec');},10000) 被执行
-
setTimeout 返回undefined
- 已到达
await:(注意:为清楚起见,我将跳过下面的一些细节。)
- 通常,当您执行
await p 时,p 是一个承诺(或至少类似于承诺)。由于您已经在 undefined 上使用了它,因此 await 将 undefined 包装在一个承诺中,就好像它调用了 Promise.resolve(undefined) 并将其用作 p 而不是 undefined。
- 函数中
await 之后的所有代码都附加到p 作为p 满足时的处理程序(因为您没有使用try/catch - 这很好 -所以没有拒绝处理程序)。当您将履行或拒绝处理程序附加到承诺时,您会创建一个新承诺,该承诺会根据原始承诺发生的情况以及(如果相关)调用履行或拒绝处理程序时发生的情况来解决。让我们将这个新承诺称为p2。
- 通常,
p 还不会被解决,但在这种情况下它是,所以履行处理程序(imaAsyncFunction 中的其余代码,在await 之后)计划运行一次当前同步工作完成。如果p 尚未解决,这将不会发生(稍后会在p 解决时发生。)
- 由于函数中没有任何其他
await 表达式,因此隐式创建的承诺imaAsyncFunction(我们称之为p3)解析为p2。这意味着当p2 结算时,来自imaAsyncFunction 的promise 以相同的方式结算(它以与p2 相同的履行值履行,或以p2 的拒绝原因被拒绝)。
-
imaAsyncFunction 返回p3。
- 对
imaAsyncFunction的调用已经完成,所以下一条语句被执行:console.log('bla bla bla');
- 代码执行到了脚本的末尾,这意味着所有同步代码已经运行完毕。
- 运行上述步骤 2.2 中安排的履行处理程序代码:
- 它执行
console.log(res)和console.log('is After?!?')。
- 它用
undefined 实现p2(因为函数中没有return x)。
- 这会安排
p3 的履行,因为p3 已解析为p2。这样做会安排执行 p3 的履行处理程序,但它没有任何 - 在 imaAsyncFunction() 的返回值上没有使用 await 或 .then 或 .catch 等。李>
¹该声明有一个警告:当您将履行或拒绝处理程序附加到承诺时,对该处理程序的调用始终是异步的即使承诺已经解决。那是因为如果 promise 没有解决,它将是异步的,如果在某些情况下对处理程序的调用是同步的,但在其他情况下是异步的,那么它会很混乱,所以它总是异步完成的。但这实际上是关于 Promise 或 async 函数的唯一事情,它使任何事情异步,其余的只是观察已经异步的事情。