在 JavaScript 中无需等待的异步函数

我有两个函数,ab,它们是异步的,前者没有 await,后者有 await。它们都将某些内容记录到控制台并返回 undefined。在调用其中一个函数之后,我将记录另一条消息,并查看该消息是在执行函数体之前还是之后写入的。

function someMath() {
for (let i = 0; i < 9000000; i++) { Math.sqrt(i**5) }
}


function timeout(n) {
return new Promise(cb => setTimeout(cb, n))
}


// ------------------------------------------------- a (no await)
async function a() {
someMath()
console.log('in a (no await)')
}


// ---------------------------------------------------- b (await)
async function b() {
await timeout(100)
console.log('in b (await)')
}


clear.onclick = console.clear


aButton.onclick = function() {
console.log('clicked on a button')
a()
console.log('after a (no await) call')
}


bButton.onclick = function() {
console.log('clicked on b button')
b()
console.log('after b (await) call')
}
<button id="aButton">test without await (a)</button>
<button id="bButton">test with await (b)</button>
<button id="clear">clear console</button>

如果您在启动测试时没有使用 await,那么这个函数看起来就像是同步的一样。但是对于 await,消息是 倒过来,因为函数是异步执行的。

当不存在 await关键字时,JavaScript 如何执行 async函数?


实际用例: 我有一个有条件执行的 await关键字,为了呈现我的元素,我需要知道函数是否同步执行:

async function initializeComponent(stuff) {
if (stuff === undefined)
stuff = await getStuff()
// Initialize


if (/* Context has been blocked */)
renderComponent() // Render again if stuff had to be loaded
}


initializeComponent()
renderComponent()

P.S: 标题有 JavaScript 关键字,以避免与其他语言(即 不等待地使用异步)中的相同问题混淆

163901 次浏览

The function is executed the same with or without await. What await does is automatically wait for the promise that's returned by the function to be resolved.

await timeout(1000);
more code here;

is roughly equivalent to:

timeout(1000).then(function() {
more code here;
});

The async function declaration simply makes the function automatically return a promise that's resolved when the function returns.

Mozilla documentation:

An async function can contain an await expression, that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.

As you assumed, if no await is present, the execution is not paused and your code will then be executed synchronously as normal.

Everything is synchronous until a Javascript asynchronous function is executed. In using async-await await is asynchronous and everything after await is placed in event queue. Similar to .then().

To better explain take this example:

function main() {
return new Promise( resolve => {
console.log(3);
resolve(4);
console.log(5);
});
}


async function f(){
console.log(2);
let r = await main();
console.log(r);
}


console.log(1);
f();
console.log(6);

As await is asynchronous and rest all is synchronous including promise thus output is

1
2
3
5
6
// Async happened, await for main()
4

Similar behavior for main() without promise too:

function main() {
console.log(3);
return 4;
}


async function f(){
console.log(2);
let r = await main();
console.log(r);
}


console.log(1);
f();
console.log(5);

Output:

1
2
3
5
// Asynchronous happened, await for main()
4

Just removing await will make whole async function synchronous which it is.

function main() {
console.log(3);
return 4;
}


async function f(){
console.log(2);
let r = main();
console.log(r);
}


console.log(1);
f();
console.log(5);

Output:

1
2
3
4
5

As other answers say/indicate: an async function just runs on spot until it encounters an await - if there is no await, it runs completely.

What may be worth adding that async unconditionally makes your result a Promise. So if you return something, there is a difference already and you simply can not get the result without returning to the JS engine first (similarly to event handling):

async function four(){
console.log("  I am four");
return 4;
}
console.log(1);
let result=four();
console.log(2,"It is not four:",result,"Is it a promise ?", result instanceof Promise);
result.then(function(x){console.log(x,"(from then)");});
console.log(3);