JavaScript 中没有 await 的异步函数

IT技术 javascript asynchronous async-await
2021-03-12 12:19:47

我有两个函数,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当函数异步执行,消息会被反转

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


实际用例:我有一个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()

PS:标题有 JavaScript 关键字,以避免与其他语言中的相同问题混淆(即Using async without await

4个回答

Mozilla 文档

异步函数可以包含一个 await 表达式,它暂停异步函数的执行并等待传递的 Promise 的解析,然后恢复异步函数的执行并返回解析的值。

正如您所假设的,如果不存在 await,则不会暂停执行,然后您的代码将以非阻塞方式执行。

在返回Promise但不使用的函数中声明“异步”的一个好处await是异常将被拒绝而不是同步抛出。例如const result = someAsyncFunctionWithoutAwait().catch(handleRejection)
2021-04-17 12:19:47
换句话说,这个答案不应该说“如果不存在等待,则执行不会暂停,但您的代码仍将以非阻塞方式执行”而不是“如果不存在等待,则执行不会暂停并且然后您的代码将同步执行”?此外,如果不存在 async 和 await,您的代码仍将是非阻塞的(例如,使用 async 关键字声明函数而不使用 await 等效于不使用 async 关键字声明相同的函数)。
2021-04-18 12:19:47
看它的一个好方法是异步/等待可以让你同步异步代码:async function dummy(){ /*...*/ return Promise.resolve(/*...*/); } async dummyAsync(){ dummy(); nextDummy(); } async dummySync(){ await dummy(); nextDummy(); }dummyAsync 中nextDummy(),在dummy()完成之前不会停止执行它的异步dummySync nextDummy()中,直到来自dummy()解决(返回)的Promise才执行它是同步的,或按程序编写的异步代码。@AdrianPop 完美地用于声明异步而不是调用等待。
2021-04-24 12:19:47
冗余async关键字是否有 eslint 规则我不认为同步函数应该有它
2021-05-06 12:19:47
哦,是的,就是那个。不知何故错过了 :D 谢谢
2021-05-15 12:19:47

在执行 JavaScript 异步函数之前,一切都是同步的。在使用 async-await 时,await是异步的,await 之后的所有内容都放在事件队列中。它类似于.then().

为了更好地解释,举个例子:

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);

由于await是异步的,其余的都是同步的,包括Promise,因此输出是:

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

类似的行为main()也没有Promise:

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);

输出:

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

只是删除await将使整个async功能同步。

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);

输出:

1
2
3
4
5
事件队列中的代码(await之后的所有内容是否总是在主线程完成后运行?我的意思是,在您的两个示例中,在您最后一次console.log运行事件队列之后,“等待”的代码最终会执行。如果我们有更多的指令和更多的代码,那么在最后一条指令之后等待的代码还会运行吗?
2021-04-16 12:19:47
await只能在async函数内部使用
2021-04-22 12:19:47
您还可以添加一个执行 var g = await f() 的函数,因为 f() 是异步的,如果您不想阻塞主执行线程,可能需要在长时间运行的进程中等待。
2021-05-02 12:19:47
请注意,这是 ES11 之前的旧实现。在 ES11 中,事情发生了一些变化。但这仍然有效。
2021-05-11 12:19:47

无论是否使用 ,该函数的执行方式都相同await什么await是自动等待由函数返回的Promise被解析。

await timeout(1000);
more code here;

大致相当于:

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

async function声明只是使功能自动返回的问题得以解决函数返回时的Promise。

有用的答案 - 更长的解释也许也试试这个博客 - medium.com/javascript-in-plain-english/...
2021-04-16 12:19:47

正如其他答案所说/表明的那样: anasync function只是在现场运行,直到遇到一个await- 如果没有await,则它会完全运行。

可能值得添加的是async无条件地使您的结果成为Promise. 所以如果你返回一些东西,已经有区别了,如果不首先返回到 JS 引擎,你根本无法得到结果(类似于事件处理):

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);

@UlysseBN 我想我找到了中间立场:-)。虽然{}这里出现的不是很壮观,但已经说明了并不能4确定,值得一提的是,在浏览器的JS控制台中可以看到并查看实际对象。
2021-04-21 12:19:47
是的,我猜这就是你所期望的!不幸的是,我不知道在 JS 中显示实例来自的类的好方法......(但是instanceof
2021-04-22 12:19:47