【高频考点精讲】async/await原理剖析:Generator和Promise的完美结合

async/await原理剖析:Generator和Promise的完美结合

今天咱们聊聊async/await,这玩意儿用起来是真香,但你知道它背后是怎么运作的吗?其实它就是GeneratorPromise的"爱情结晶"。

1. 先搞懂Generator

Generator(生成器)是ES6引入的一个特殊函数,它能在执行过程中暂停和恢复。听起来像不像async/await?没错,async/await的底层就是基于Generator的。

javascript 复制代码
function* myGenerator() {
  yield '第一步';  // 暂停,返回'第一步'
  yield '第二步';  // 再次暂停,返回'第二步'
  return '结束';   // 结束生成器
}

const gen = myGenerator();
console.log(gen.next());  // { value: '第一步', done: false }  
console.log(gen.next());  // { value: '第二步', done: false }  
console.log(gen.next());  // { value: '结束', done: true }  

yield就像是一个"暂停按钮",每次调用next(),函数就会执行到下一个yieldreturn

全栈老李小贴士Generator本身并不能自动执行异步操作,它只是提供了一种"暂停-恢复"的机制。

2. Promise:异步操作的基石

Promise大家都熟,它代表一个异步操作的最终状态(成功或失败)。async/awaitawait后面必须跟一个Promise,否则它就没意义了。

javascript 复制代码
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => resolve('数据来了'), 1000);
  });
}

fetchData().then(data => console.log(data));  // 1秒后输出"数据来了"

3. async/awaitGenerator + Promise的完美结合

async/await本质上是一个语法糖,它让Generator自动执行,并且让yield等待Promise完成。

3.1 async函数返回一个Promise

javascript 复制代码
async function getData() {
  return "全栈老李的数据";
}

getData().then(data => console.log(data));  // 输出"全栈老李的数据"

3.2 await让异步代码看起来像同步

javascript 复制代码
async function fetchUser() {
  const response = await fetch('https://api.example.com/user');  // 等待Promise完成
  const data = await response.json();  // 再等待解析JSON
  console.log(data);
}

全栈老李解析await其实就是yield的升级版,它会自动等待Promise完成,然后继续执行后续代码。

4. 手写一个简化版async/await

为了更深入理解,咱们用GeneratorPromise模拟async/await

javascript 复制代码
function runGenerator(generatorFunc) {
  const gen = generatorFunc();
  
  function handleNext(value) {
    const result = gen.next(value);
    if (result.done) return Promise.resolve(result.value);
    
    return Promise.resolve(result.value)
      .then(handleNext)
      .catch(err => gen.throw(err));  // 错误处理
  }
  
  return handleNext();
}

function* mockAsync() {
  const data1 = yield Promise.resolve('第一步');
  console.log(data1);  // "第一步"
  const data2 = yield Promise.resolve('第二步');
  console.log(data2);  // "第二步"
}

runGenerator(mockAsync);

全栈老李解读

  1. runGenerator负责自动执行Generator
  2. 每次yield返回一个PromisehandleNext会等待它完成,再把结果传给下一个next()
  3. 如果Promise被拒绝,会通过gen.throw抛出错误。

5. 使用场景

5.1 多个异步操作依赖执行

javascript 复制代码
async function getUserPosts(userId) {
  const user = await fetch(`/users/${userId}`);
  const posts = await fetch(`/users/${userId}/posts`);
  return { user, posts };
}

5.2 错误处理更直观

javascript 复制代码
async function fetchData() {
  try {
    const data = await fetch('/api/data');
    return data.json();
  } catch (error) {
    console.error('全栈老李提醒:请求失败', error);
  }
}

6. 课后作业(面试题)

题目:下面代码的输出顺序是什么?

javascript 复制代码
async function test() {
  console.log(1);
  await Promise.resolve().then(() => console.log(2));
  console.log(3);
}

console.log(4);
test();
console.log(5);

要求

  1. 在评论区写出你的答案和解析。
  2. 我会随机抽几位同学的答案进行点评哦~

全栈老李提示 :注意await的微任务机制和事件循环的关系!


好了,今天的内容就到这里,如果你觉得有用,别忘了点赞关注"全栈老李",咱们下期再见! 🚀

相关推荐
邝邝邝邝丹23 分钟前
React学习———React Router
前端·学习·react.js
Yvonne爱编码1 小时前
CSS- 2.1 实战之图文混排、表格、表单
前端·css·html·github·状态模式·html5·hbuilder
前端小巷子1 小时前
CSS面试题汇总
前端·css·面试
绝美焦栖1 小时前
vue复杂数据类型多层嵌套的监听
前端·javascript·vue.js
xixixin_2 小时前
【Vite】前端开发服务器的配置
服务器·前端·网络
.生产的驴2 小时前
Vue3 加快页面加载速度 使用CDN外部库的加载 提升页面打开速度 服务器分发
运维·服务器·前端·vue.js·分布式·前端框架·vue
史迪仔01122 小时前
Python生成器:高效处理大数据的秘密武器
前端·数据库·python
蓝婷儿3 小时前
前端面试每日三题 - Day 34
前端·面试·职场和发展
CopyLower3 小时前
苹果计划将AI搜索集成至Safari:谷歌搜索下降引发的市场变革
前端·人工智能·safari
郝开4 小时前
扩展:React 项目执行 yarn eject 后的 package.json 变化详解及参数解析
react.js·前端框架·react