You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中async函数用await与不用await的差异及代码等价性问询

在async函数中使用await与不使用await的区别

先给你说最核心的点:await就是async函数里用来「暂停执行、等Promise跑完」的关键,不用它的话,Promise就只是个普通的异步任务,根本不会拦住async函数的同步流程。具体可以拆成这几个细节:

  • 执行流程是否阻塞:

    • 不用await:async函数里的Promise会被立刻创建并丢进异步队列,但函数本身该往下走就往下走,完全不等Promise完成。比如你写:
      async function test() {
        let p = Promise.resolve('hello');
        console.log('after creating promise');
      }
      test();
      
      这里after creating promise会在Promise还没resolve的时候就打印出来,根本不会等。
    • 用await:碰到await p时,async函数会立刻暂停,把执行权还给调用栈,直到这个Promise变成resolved状态,才会接着执行后面的代码,而且await会自动把Promise的resolve结果取出来。上面的例子改成await p; console.log('after creating promise'),那这句话就得等Promise resolve完才会打印。
  • 返回值怎么处理:

    • 不用await:如果你在async函数里返回一个Promise,函数会直接把这个Promise当自己的返回值,但要是只是创建Promise却不await,那这个Promise的结果跟函数后续代码一点关系都没有。
    • 用await:你可以直接把await的结果赋值给变量,比如let res = await Promise.resolve(1),res拿到的就是1,不是那个Promise对象,省得你再写.then()取结果。
  • 错误怎么捕获:

    • 不用await:如果Promise rejected了,你得用.catch()去抓错误,不然就会变成未捕获的Promise报错。
    • 用await:直接把await放进try/catch块里就行,写法跟同步代码抓错误一模一样,比如:
      async function test() {
        try {
          await Promise.reject('出错了');
        } catch (err) {
          console.log(err); // 会打印'出错了'
        }
      }
      

两段代码的等价性分析

现在来对比你给的两段代码,咱们从执行时间、输出结果、同步/异步逻辑三个方面说清楚:

代码1:

(async () => { 
  let i = 100000; 
  while(i--); 
})();

代码2:

(async () => { 
  let promise = new Promise((resolve, reject) => { 
    let i = 100000; 
    while(i--); 
    return resolve(); 
  }); 
  await promise; 
})();

1. 执行时间是否相同?

几乎一样,但代码2会多一丢丢可以忽略的开销。因为代码1里的while循环是直接在async函数的同步阶段跑完的;代码2里的while循环是在Promise的executor函数里执行的,而executor函数是创建Promise时就同步执行的,所以while循环的执行时间和代码1完全一致。但代码2多了创建Promise对象、处理await的异步调度开销,不过这个开销极小,几乎感觉不到。

2. console.log输出结果是否一致?

如果两段代码都没写console.log,那输出当然都是空的。但要是我们在两段代码末尾加个console.log('done'),再在外面加个console.log('start')和console.log('end'),差别就出来了:

  • 代码1的输出顺序是:start → done → end。因为代码1里没有await,整个async函数是同步执行的,while循环跑完就立刻打印done,然后才会执行外面的end。
  • 代码2的输出顺序是:start → end → done。因为await会把后面的代码放到微任务队列里,得等当前所有同步任务(包括外面的end)都跑完,才会从微任务队列里取出代码打印done。

所以只要有console.log,输出结果的顺序是完全不一样的!

3. 同步/异步执行逻辑是否相同?

完全不同:

  • 代码1:整个async函数是纯同步执行的。虽然它是async函数,但里面没有任何异步操作或者await,所以它跟普通函数没区别,同步跑完所有代码,最后返回一个resolved的Promise(async函数默认返回resolved的Promise,除非你自己返回了其他Promise)。
  • 代码2:虽然Promise的executor是同步执行的,但await promise触发了async函数的暂停,把后续代码(如果有的话)丢进了微任务队列。它的执行流程是:
    1. 同步创建Promise,立刻执行executor里的while循环(同步跑完)。
    2. 调用resolve(),Promise变成resolved状态。
    3. 碰到await,async函数暂停,把执行权还给调用栈。
    4. 等当前所有同步任务都执行完,再从微任务队列里取出await后面的代码继续执行。

简单说,代码1就是个披着async外衣的同步函数,代码2则是真正包含了异步调度逻辑的函数——哪怕while循环是同步的,但await把整个函数的后半段变成了微任务。


内容的提问来源于stack exchange,提问作者Michael Hsu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:03:25