# ❓JS 异步解决方案的发展历程以及优缺点
# 回调函数形式(callback)
ajax('', () => {
// callback
ajax('', () => {
// callback
ajax('', () => {
// ...
})
})
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 优点
- 解决同步问题
# 缺点
- 容易导致回调地狱
- 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转)
- 嵌套函数过多的多话,很难处理错误
# Promise 形式
- pending 初始状态
- fulfilled 操作成功
- rejected 操作失败
new Promise((resolve, reject) => {
// resolve()
// or
// reject()
})
.then(() => {})
.catch(() => {})
1
2
3
4
5
6
7
2
3
4
5
6
7
# 优点
- 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
Promise
对象提供统一的的接口,使得控制异步操作更加容易
# 缺点
- 无法取消,一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,
Promise
内部抛出的错误,不会反映到外部 - 当处于
pending
状态时,无法得知目前进展到哪一个阶段(刚开始还是即将完成)
# Generator
function* helloWorldGenerator() {
yield 'hello'
yield 'world'
return 'ending'
}
var hw = helloWorldGenerator()
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true } 以后再次调用还是这个值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 优点
- 异步操作同步化表达,改写回调函数
- 控制流管理,可以改善大量的 promise 语法
- 部署 Iterator 接口,利用
Generator
函数,可以在任意对象上部署 Iterator 接口。 - 作为数据结构,更确切地说,可以看作是一个数组结构,因为
Generator
函数可以返回一系列的值,这意味着它可以对任意表达式,提供类似数组的接口。
# 缺点
- 没有内置执行器,需要手动执行
- 语义化不清楚,不容易阅读理解
# Async/Await
就是 Generator
函数的语法糖,使得异步操作变得更加方便。
const asyncReadFile = async function() {
const f1 = await readFile('/etc/fstab')
const f2 = await readFile('/etc/shells')
console.log(f1.toString())
console.log(f2.toString())
}
1
2
3
4
5
6
2
3
4
5
6
# 优点
- 内置执行器
- 更好的语义,async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果
- 更广的适用性,await 命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)
- 返回值是 Promise, 这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用 then 方法指定下一步的操作