async/await原理剖析:Generator和Promise的完美结合
今天咱们聊聊async/await
,这玩意儿用起来是真香,但你知道它背后是怎么运作的吗?其实它就是Generator
和Promise
的"爱情结晶"。
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()
,函数就会执行到下一个yield
或return
。
全栈老李小贴士 :Generator
本身并不能自动执行异步操作,它只是提供了一种"暂停-恢复"的机制。
2. Promise
:异步操作的基石
Promise
大家都熟,它代表一个异步操作的最终状态(成功或失败)。async/await
的await
后面必须跟一个Promise
,否则它就没意义了。
javascript
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve('数据来了'), 1000);
});
}
fetchData().then(data => console.log(data)); // 1秒后输出"数据来了"
3. async/await
:Generator
+ 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
为了更深入理解,咱们用Generator
和Promise
模拟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);
全栈老李解读:
runGenerator
负责自动执行Generator
。- 每次
yield
返回一个Promise
,handleNext
会等待它完成,再把结果传给下一个next()
。 - 如果
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);
要求:
- 在评论区写出你的答案和解析。
- 我会随机抽几位同学的答案进行点评哦~
全栈老李提示 :注意await
的微任务机制和事件循环的关系!
好了,今天的内容就到这里,如果你觉得有用,别忘了点赞关注"全栈老李",咱们下期再见! 🚀