为什么在JavaScript中,await只能在异步函数中使用?

32

刚阅读完这个教程,让我不解的是为什么await只能在async函数中使用。

根据教程所述:

如上所述,await只能在async函数内部使用。

据我理解,async将函数返回对象封装成Promise,以便调用者可以使用.then()方法。

async function f() {
  return 1;
}

f().then(alert); // 1

await 只是在 async 函数内等待 Promise 完成。

async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });

  let result = await promise; // wait till the promise resolves (*)

  alert(result); // "done!"
}

f();

在我看来,它们的用法并不相关,能否有人解释一下?


7
这只是功能设计的方式。将一个函数标记为“async”的唯一原因是它在内部使用了“await”。请记住,该语言必须继续完全正常地处理2003年编写的代码。 - Pointy
2
f() 返回 result 时会发生什么?调用函数将立即获得返回值——它不知道你在 f() 中使用了 await。使用异步函数时,返回值将是一个 Promise。 - Mark
1
从C#中复制并粘贴。异步/承诺的语法糖涂层。当我第一次看到它时,感到很惊讶。 - int-i
3
根据OP的观点,似乎“async”是多余的,解析器可以在有“await”的情况下自动识别函数是否是异步的,而无需人为干预。但也许这种方法较慢,或者不支持“eval”,或者存在其他要注意的问题。 - dandavis
据我理解,如果在异步范围之外允许使用 await,那么通过将所有异步操作(例如 http 请求)等待,就可以冻结整个程序。结果,用户界面无法响应。这不是 JavaScript 的设计模式。因此,通过限制异步范围内的 await,我们可以确保程序不会被阻塞。顺便说一下,这个特性在许多其他编程语言中也可用。 - Abdu
显示剩余6条评论
2个回答

18

代码在await上变成异步 - 我们不知道要返回什么

await除了等待Promise解析之外,还会立即将代码执行返回给调用者。 await后面的所有代码都是异步的。

  • async是返回Promise的语法糖。
  • 如果您不想在await处返回Promise,在异步代码中有什么合理的替代方法?

让我们看一下以下错误代码以查看返回值问题:

function f() {
  // Execution becomes asynchronous after the next line, what do we want to return to the caller?
  let result = await myPromise;

  // No point returning string in async code since the caller has already moved forward.
  return "function finished";
}

我们可以提出另一个问题:为什么没有同步版本的 await,而不需要将代码更改为异步?

我认为原因有很多,良好的设计是使异步代码变成同步代码变得困难。例如,这将使人们在等待异步函数返回时意外地让整个应用程序冻结。


为了进一步说明 asyncawait 的运行时顺序:

async function f() {

  for(var i = 0; i < 1000000; i++); // create some synchronous delay

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });

  console.log("message inside f before returning, still synchronous, i = " + i);

  // let's await and at the same time return the promise to the caller
  let result = await promise;
  console.log("message inside f after await, asynchronous now");

  console.log(result); // "done!"

  return "function finished";
}

let myresult = f();
console.log("message outside f, immediately after calling f");

控制台日志输出为:

message inside f before returning, still synchronous, i = 1000000 
message message outside f, immediately after calling f 
message inside f after await, asynchronous now 
done!

1
"除了等待 Promise 解决之外,await 还会立即将代码执行返回给调用者。" 第一句话对我很有帮助。 - Tao Zhang

3

asyncawait 都是元关键字,它们允许以同步的方式编写异步代码。一个 async 函数会提前告诉编译器函数将返回一个 Promise,并且不会立即解决值。为了使用 await 并且不阻塞线程,必须使用 async

async function f() {
    return await fetch('/api/endpoint');
}

等同于

function f() {
    return new Promise((resolve,reject) => {
        return fetch('/api/endpoint')
        .then(resolve);
    });
}

13
不过这并没有回答提问者的问题。 - EugZol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接