【高频考点精讲】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的微任务机制和事件循环的关系!


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

相关推荐
花生侠21 分钟前
记录:前端项目使用pnpm+husky(v9)+commitlint,提交代码格式化校验
前端
猿榜22 分钟前
魔改编译-永久解决selenium痕迹(二)
javascript·python
阿幸软件杂货间26 分钟前
阿幸课堂随机点名
android·开发语言·javascript
一涯28 分钟前
Cursor操作面板改为垂直
前端
我要让全世界知道我很低调35 分钟前
记一次 Vite 下的白屏优化
前端·css
threelab36 分钟前
three案例 Three.js波纹效果演示
开发语言·javascript·ecmascript
1undefined237 分钟前
element中的Table改造成虚拟列表,并封装成hooks
前端·javascript·vue.js
蓝倾1 小时前
淘宝批量获取商品SKU实战案例
前端·后端·api
comelong1 小时前
Docker容器启动postgres端口映射失败问题
前端