核心内容:语言对于复杂流程控制的探索 ifelse、switch、while能解决所有问题,但是不一定是合理的解。
=========
1. Promise
- Promise提供了一种新的处理异步操作的方式:异步操作内容、不同状态的处理函数、操作状态;等待异步操作处理完以后,根据不同的状态调用对应的处理函数。
- Promise可以通过链式的方式处理一串异步操作,简化了回调地狱问题;同时Promise提供错误处理,异步操作组合。
- Promise.then 注册的函数是放在微任务里面调用的。
- Promise的问题:很长的链式调用书写和维护都很麻烦。javascript对于复杂异步流程的控制问题没有根本解决。
2. 生成器函数(Generator Function)
2.1 普通函数(Function)与生成器函数(Generator Function)的比较
2.1.1 普通函数
- 执行流程:
- 当函数被调用时,立即开始执行。
- 函数体内的代码从上到下顺序执行,直到遇到 return 语句或函数末尾。
- 执行完毕后,立即返回到调用处,继续执行调用函数的后续代码。
- 内部实现:
- 调用时,在调用栈(call stack)中创建新的栈帧(stack frame)。
- 栈帧包含函数的局部变量、参数和返回地址等信息。
- 函数执行完毕后,栈帧被销毁,控制权返回给调用者。
- 特征:
- 一旦开始执行,会一直运行到结束,中途不会暂停或让出控制权。
- 每次调用都是独立的,不保留上次执行的状态。
2.1.2 生成器函数
- 执行流程:
- 调用生成器函数时,不会立即执行函数体,而是返回一个生成器对象。
- 通过调用生成器对象的 next() 方法,函数开始执行或从上次暂停处继续执行。
- 执行到 yield 语句时,函数暂停并返回 yield 后的值。
- 控制权返回给调用者,调用者可以处理 yield 的值并决定何时恢复生成器的执行。
- 内部实现:
- 每次调用 next() 时,生成器函数的执行上下文被推入调用栈。
- 函数执行到 yield 语句后,保存当前的执行状态(包括局部变量和程序计数器)。
- 执行上下文从调用栈中弹出,但状态信息被保留在堆内存中。
- 下次调用 next() 时,恢复保存的状态并继续执行。
- 特征:
- 可以在执行过程中多次暂停和恢复。
- 保留函数的执行状态,实现延迟计算和惰性求值。
2.2 Generator原本的目的
Generator函数最初的主要目的是创建自定义的迭代器。
迭代器是一种可以遍历集合的对象,而 Generator函数提供了一种简单的方法来创建这些迭代器。
在Python等于语言中都有类似的实现。
- 生成有限或无限序列
- 实现复杂的迭代逻辑
- 惰性计算(只在需要时才生成下一个值)
- 与语言的迭代机制(如 for...of 循环)无缝集成
Generator的特性决定了Generator可以很好的控制异步流程
2.3 Generator在控制流程方面的特性(被意外放大的作用)
其实还是基于可以在执行过程中多次暂停和恢复这个特性,可以结合Promise将异步控制流程书写的像同步一样。这个是在实际应用中被广大程序员发现的
问题:需要一个额外的控制函数。
// fetchUserData的实现已经很想在用同步的方式去写异步代码,
function* fetchUserData() {
try {
const user = yield fetch('/api/user').then(r => r.json());
const posts = yield fetch(`/api/posts?userId=${user.id}`).then(r => r.json());
const comments = yield fetch(`/api/comments?userId=${user.id}`).then(r => r.json());
return { user, posts, comments };
} catch (error) {
console.error('Error fetching user data:', error);
}
}
// 这个函数用来控制执行
function runGenerator(generatorFunction) {
const generator = generatorFunction();
function handle(result) {
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(
res => handle(generator.next(res)),
err => handle(generator.throw(err))
);
}
return handle(generator.next());
}
runGenerator(fetchUserData).then(data => console.log(data));
3. async/await
- Generator和Promise可以来简化异步流程的书写,但是需要一个额外的控制函数(runGenerator),所以ES6就搞了一个语法糖来简化。
- async/await 它提供了一种更简洁、更直观的方式来编写异步代码,而无需显式使用 Generator 或编写执行器函数。
- async 相当于声明 生成函数
- await 相当于yield
- 隐式的执行器:自动处理Promise的解析;恢复Generator的恢复。