You need to enable JavaScript to run this app. JS异步函数中为何修改变量前,打印的await结果已包含修改值
优惠活动
大模型
产品
解决方案
定价
更多

JS异步函数中为何修改变量前,打印的await结果已包含修改值

问题本质原因

整个现象由两个JavaScript的基础机制叠加导致,不存在代码执行顺序颠倒的问题:

  • 非原始值的引用传递特性
    代码里的对象a、嵌套的records数组都属于非原始值,在函数传参、Promise返回值传递的过程中,不会生成独立的完整数据副本,传递的永远是指向内存数据的引用地址。asyncfunction的形参prop、await得到的res1,和你最开始定义的a,本质上都是同一块内存数据的引用句柄,对任意一个句柄的修改,都会直接作用到所有句柄指向的原数据上。
  • 控制台的引用值打印延迟读取机制
    很多开发者误以为console.log(obj)执行的瞬间,会把obj当时的完整内容做快照后再输出。实际上针对对象、数组这类引用类型,控制台只会先保存这个对象的引用地址,等主线程空闲、渲染控制台日志的时候,才会顺着这个地址读取最新的内存值展示出来。
对应代码的实际执行时序
  1. 组件初始化,定义对象a,此时a.data.records的初始值为[1,2,3]
  2. useEffect触发执行fetch,调用asyncfunction(a):这里传入的不是a的完整拷贝,只是a的引用地址
  3. 500ms定时器到期,执行resolve(prop),把同一个引用地址作为Promise的结果返回
  4. await等待完成,将这个引用地址赋值给res1,此时res1.data.records和原a.data.records是同一个数组
  5. 执行console.log(res1):控制台收到数组的引用,暂存地址但没有立刻读取数组内容
  6. 紧接着执行同步代码a.data.records.push(11111):因为操作的是同一块内存地址,这次push直接修改了共享的数组内容
  7. 主线程空闲开始渲染控制台内容,顺着之前存的数组引用读取最新值,自然就看到了push之后新增的11111
快速验证方式

如果想让控制台打印出push之前的初始值,只需要在打印时主动生成独立的值快照,打断和原数据的引用关联即可:

  • 把打印语句改成console.log([...res1.data.records])
  • 此时控制台拿到的是数组展开后生成的独立副本,保存的是打印时刻的[1,2,3]快照,后续对原数组的修改不会影响最终的打印结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 21:45:04