gpt4 book ai didi

javascript - 为什么这个异步函数同步运行?

转载 作者:行者123 更新时间:2023-12-05 08:49:01 25 4
gpt4 key购买 nike

这是我的代码:

async function test() {
console.log('TEST');
}

function go() {
console.log('one');
test();
console.log('two');
}

go()

我已将 test 函数标记为 async,并且我await 中使用 go 调用它的方法,所以我希望输出是这样的:

one
two
TEST

但是输出结果是这样的:

one
TEST
two

在我的实际用例中,test 是一个函数,它包装了一些我实际上希望异步发生的长处理逻辑,而不是按顺序发生。

为什么这里没有发生这种情况,我该如何解决?

最佳答案

async 函数的主体同步执行,直到第一个 await 语句。当它遇到 await 表达式时,它将控制权交给调用函数并暂停。 await 表达式之后的部分是异步完成的。

根据 MDN docs :

The body of an async function can be thought of as being split by zeroor more await expressions. Top-level code, up to and including thefirst await expression (if there is one), is run synchronously. Inthis way, an async function without an await expression will runsynchronously. If there is an await expression inside the functionbody, however, the async function will always complete asynchronously.

Code after each await expression can be thought of as existing in a.then callback. In this way a promise chain is progressivelyconstructed with each reentrant step through the function. The returnvalue forms the final link in the chain.

这可以通过以下没有 await 的示例观察到,其中函数体是同步执行的:

async function testSync() {
console.log("Runs synchronously");
}


console.log(1);

testSync();

console.log(2);

这是一个示例,其中 awaited Promise 使行为在 await 之后异步:

async function testAsync() {
console.log("Runs synchronously until here");
await myPromise();
console.log("Runs asynchronously here");
}

function myPromise() {
return Promise.resolve();
}


console.log(1);

testAsync();

console.log(2);

这可以通过多种方式异步执行。您可以将函数包装在 setTimeout 调用中:

function test() {
console.log("I want to execute asynchronously");
}

console.log(1);
setTimeout(test, 0);
console.log(2);

或者您可以通过 promise 回调来完成:

function test(){
console.log("I want to run asynchronously");
}
console.log(1);
Promise.resolve().then(test).catch(e => console.error(e));
console.log(2);

同样可以使用 queueMicrotask 完成,文档 here :

function test(){
console.log("I want to run asynchronously");
}
console.log(1);
queueMicrotask(test);
console.log(2);

setTimeout 和使用 Promise 回调的方法之间的区别在于它们如何排队等待执行。有两个任务队列,一个是初始程序执行,setTimeoutsetIntervalrequestAnimationframe等回调的任务队列,另一个是 promise 回调排队的微任务队列。

当你从任务队列中加入一个任务并且还有剩余的任务时,事件循环将检查微任务队列并执行它们所有,然后再占用下一个任务来自任务队列的任务。

这是一个演示这一点的片段:

function testTaskQueue(){
console.log("Enqueued in the task queue");
}
function testMicroTaskQueue(){
console.log("Enqueued in the microtask queue");
}

console.log(1);
setTimeout(testTaskQueue, 0);
Promise.resolve().then(testMicroTaskQueue);
queueMicrotask(testMicroTaskQueue);
console.log(2)

因此,根据这一点,您可以创建自己的async 包装器并将您的函数作为回调传递:

function makeAsync(callback, ...params) {
//enqueued intask queue
setTimeout(callback, 0, ...params);
//Or using microtasks
Promise.resolve().then(() => test(...params)).catch(console.error);
}

function test(...params) {
console.log("I want to run asynchronoulsy", ...params);
}
console.log(1)
makeAsync(test, 3);
console.log(2);

关于javascript - 为什么这个异步函数同步运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65273364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com