JavaScript 异步编程发展史
2023-05-22· 8min
#同步、异步的概念
- 同步(Synchronous, sync)
- 单线程编程中,代码是同步运行的(但同步不意味着所有代码同时运行,而是指在一个控制流序列中按顺序执行)
- 异步(Asynchronous, async)
- 不按照代码顺序执行
异步编程方案:异步回调、事件监听、定时器、发布/订阅模式、Promise、Generator、async/await...
#一、回调函数(Callback)
- 优点:容易理解和实现、同时解决了因任务排队耗时久的同步执行问题
- 缺点:会造成回调地狱(嵌套层级高)、可读性差
// 举例:多个操作之间如果有先后依赖关系的话,会出现回调地狱
doSomething((result) => {
doSomething(result, (newResult) => {
doSomething(newResult, (finalResult) => {});
});
});
#二、Promise
- Promise本质上是一个函数返回的对象,可以获取异步操作的最终状态(成功、失败)
- 特点:
- Promise的状态不受外界影响:pending、fulfilled、rejected
- Promise的状态一旦改变,就不会再变(pending -> fulfilled、pending -> rejected)
- 优点:用同步的方式写异步的代码、解决了回调地狱的问题、更好的异常错误处理
- 缺点:
- 一旦新建就会立即执行,无法中途取消
- 错误需要通过回调函数捕获
#三、Generator
- Generator函数是 ES6 中提供的一种异步编程解决方案。可以理解成:是一个状态机,封装了多个内部状态,需要使用 next() 函数来继续执行后续的代码
- 特点:
- function 与函数名之间带有 *符号
- 函数体内部使用 yield 表达式,函数执行遇到 yield 就返回
- function 与函数名之间带有
- 优点:
- 可以控制函数的执行(暂停执行、恢复执行)
- 缺点
- 需要手动控制
function* doSomething() {
console.log("Start");
yield 1;
console.log("Middle");
yield 2;
console.log("End");
return 3;
}
var genr = doSomething();
console.log(genr.next()); // Start、{ value: 1, done: false }
console.log(genr.next()); // Middle、{ value: 2, done: false }
console.log(genr.next()); // End、{ value: 3, done: true }
console.log(genr.next()); // { value: undefined, done: true }
#四、async、await
- 实现原理:将 Generator 函数和自动执行器,包装在一个函数里。本质上是 Generator 的语法糖
- 优点:
- async 函数自带执行器(Generator 函数的执行则需要调用 next 方法)
- 代码清晰,不用像 Promise 写一堆 then
- 返回 Promise 对象(Generator 函数则返回迭代器对象)
- 缺点
- await 将异步代码改造成同步代码,如果多个异步操作间没有依赖,但使用 await 会导致性能降低
async function doSomething() {
console.log("Start");
await mockPause(1000);
console.log("Middle");
await mockPause(1000);
console.log("End");
return 3;
}
function mockPause(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
doSomething();
- 拓展
- 迭代器(Interator):
- 是 ES6 引入的一种新的数据结构,是一种对象,提供了一种顺序访问集合中每个元素的方式。
- 通过调用迭代器的 next() 方法,可以依次获取集合中的每个元素,并返回一个包含 value 和 done 属性的对象(value: 当前元素的值,done: 是否已经遍历完所有元素)
- 迭代器与生成器的区别:
- 迭代器(Interator)提供了一种顺序访问集合中每个元素的方式
- 生成器(Generator)则允许函数在执行过程中暂停和恢复
- 迭代器(Interator):