jS篇Async await实现同步效果的原理

async/await 之所以能让异步代码呈现出 "同步的写法和执行体验",核心在于它是 Generator 函数和 Promise 的语法糖,通过语法层面的封装,隐藏了异步操作的回调嵌套,让代码结构更接近同步逻辑。

具体来说,它的 "同步效果" 体现在两个方面:

1. 写法上的同步化

传统异步代码(如 Promise 的 then 链式调用或回调函数)需要嵌套或链式书写,而 async/await 允许用 线性代码结构 编写异步逻辑,就像写同步代码一样:

javascript

ini 复制代码
// 传统 Promise 写法(链式调用)
fetchData()
  .then(data => {
    return processData(data);
  })
  .then(result => {
    console.log(result);
  });

// async/await 写法(线性结构)
async function handleData() {
  const data = await fetchData();
  const result = await processData(data);
  console.log(result);
}

后者的代码流程和 "同步读取数据→处理数据→输出结果" 的逻辑完全一致,更符合人类的思维习惯。

2. 执行上的 "等待" 效果

await 关键字会 暂停当前函数的执行 ,等待后面的 Promise 状态变为 resolved 后,再继续执行函数内后续的代码。

这种 "暂停等待" 的特性,让异步操作看起来像 "同步阻塞" 一样:

  • 当执行到 const data = await fetchData() 时,函数会暂停,等待 fetchData() 返回的 Promise 完成。

  • 只有当 Promise 成功解析(拿到数据)后,才会把结果赋值给 data,然后执行下一行 processData(data)

注意 :这种 "暂停" 是 非阻塞的 ------JavaScript 引擎在等待 Promise 期间,会去处理其他任务(如浏览器事件、定时器等),不会卡住整个线程。这和真正的同步阻塞(如 alert())完全不同。

底层原理

async/await 的本质是利用了:

  • Promise 的异步状态管理await 后面必须跟一个 Promise(或可被转换为 Promise 的对象),依赖 Promise 来管理异步操作的完成 / 失败状态。

  • Generator 的暂停 / 恢复机制async 函数会被 JavaScript 引擎转换为类似 Generator 的结构,await 对应 Generator 中的 yield,实现函数执行的暂停和恢复。

简单说,async/await 并没有改变 JavaScript 异步单线程的本质,只是通过语法糖让异步代码的 结构更清晰、逻辑更接近同步,从而降低了异步编程的复杂度。

Generator 是 JavaScript 中一种特殊的函数类型,它的核心特点是可以暂停执行和恢复执行,通过这种 "分段续" 能力,能够更灵活地控制函数的执行流程。

Generator 函数的结构有以下几个关键特征:

1. 定义方式

通过在 function 关键字后加 * 来声明(function*),函数内部使用 yield 关键字标记暂停点:

javascript

javascript 复制代码
function* myGenerator() {
  yield '第一个值';
  yield '第二个值';
  return '结束值';
}

2. 执行机制

调用 Generator 函数不会立即执行函数体 ,而是返回一个迭代器对象(Iterator) ,通过迭代器的 next() 方法控制函数执行:

javascript

lua 复制代码
const generator = myGenerator(); // 不会执行函数体,返回迭代器

// 第一次调用 next():执行到第一个 yield 处暂停,返回 yield 的值
console.log(generator.next()); // { value: '第一个值', done: false }

// 第二次调用 next():从暂停处继续执行到下一个 yield 处暂停
console.log(generator.next()); // { value: '第二个值', done: false }

// 第三次调用 next():从暂停处继续执行到 return(或函数结束)
console.log(generator.next()); // { value: '结束值', done: true }

// 后续调用 next():函数已执行完毕,返回 undefined
console.log(generator.next()); // { value: undefined, done: true }
  • yield:相当于 "暂停标记",执行到此处会暂停,并将其后的值作为 next() 返回对象的 value
  • done:布尔值,表示函数是否执行完毕(false 未完毕,true 已完毕)。

3. 可注入数据

通过 next(arg) 可以向 Generator 函数内部注入数据,作为上一个 yield 的返回值:

javascript

lua 复制代码
function* dataGenerator() {
  const input1 = yield '请输入第一个值';
  const input2 = yield '请输入第二个值';
  return `你输入了:${input1} 和 ${input2}`;
}

const generator = dataGenerator();
console.log(generator.next()); // { value: '请输入第一个值', done: false }
console.log(generator.next('hello')); // { value: '请输入第二个值', done: false }(input1 = 'hello')
console.log(generator.next('world')); // { value: '你输入了:hello 和 world', done: true }(input2 = 'world')

4. 应用场景

Generator 的 "暂停 - 恢复" 特性使其适合处理:

  • 异步操作流程控制(async/await 的前身思路)

  • 迭代器生成(如自定义可迭代对象)

  • 状态机(如有限状态的分步执行)

简单说,Generator 函数通过 function* 定义,用 yield 标记暂停点,返回的迭代器通过 next() 控制执行,从而实现了函数执行的 "分段控制",这也是它区别于普通函数的核心特性。

相关推荐
南囝coding10 分钟前
这个仓库堪称造轮子的鼻祖,建议看看!
前端·后端
suedar25 分钟前
关于工程化的随想
前端
安琪吖33 分钟前
微前端:qiankun框架在开发中遇到的问题
前端·vue·element-ui
不爱说话郭德纲36 分钟前
🔥产品:"这功能很常见,不用原型,参考竞品就行!" 你会怎么做
前端·产品经理·产品
wordbaby44 分钟前
React 异步请求数据处理优化经验总结
前端·react.js
拉不动的猪1 小时前
回顾 pinia VS vuex
前端·vue.js·面试
Warren981 小时前
Java异常讲解
java·开发语言·前端·javascript·vue.js·ecmascript·es6
超级土豆粉1 小时前
Taro Hooks 完整分类详解
前端·javascript·react.js·taro
iphone1081 小时前
从零开始学网页开发:HTML、CSS和JavaScript的基础知识
前端·javascript·css·html·网页开发·网页
2503_928411561 小时前
7.31 CSS-2D效果
前端·css·css3