# 介绍
Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。
所谓 Promise, 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息 Promise 提供统一的 API, 各种异步操作都可以用同样的方法进行处理。
Promise 的实例有三个状态:
- Pending(进行中)
- Resolved(已完成)
- Rejected(已拒绝)
当把一件事情交给 promise 时,它的状态就是 Pending, 任务完成了状态就变成了 Resolved,没有完成失败了就变成了 Rejected。一旦从进行状态变成为其他状态就永远不能更改状态了。
Promise 的实例有两个过程:
- pending -> fulfilled : Resolved(已完成)
- pending -> rejected:Rejected(已拒绝)
Promise 的缺点:
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
- 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
# 应用
# 加载图片
function loadImg (src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
reject(new Error('加载失败!'))
}
img.src = src
})
}
2
3
4
5
6
7
8
9
10
11
12
# 简单实现
- Promise 是一个构造函数,参数接受一个函数,函数的两个参数也都是函数;
- 有一个状态属性,一个值属性存放执行成功的值,一个 reason 属性存放执行失败的原因;
class PromiseAPlus {
// 三种状态
static PENDING = 'pending'
static RESOLVED = 'resolved'
static REJECTED = 'reject'
constructor(executor) {
this.status = PENDING // 初始状态为 pending
this.value = undefined // 存储 this._resolve 即操作成功 返回的值
this.reason = undefined // 存储 this._reject 即操作失败 返回的值
executor(this._resolve.bind(this), this._reject.bind(this));
}
// 成功的回调
_resolve (value) {
this.resultValue = value
this.status = RESOLVED
}
// 失败的回调
_reject (reason) {
this.reason = reason
this.status = REJECTED
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
then 方法:
- then 方法有两个参数,一个是成功时候的回调,一个是失败的回调;
- then 方法在 resolve 或者 reject 执行之后才会执行;
- then 方法中的值是传给 resolve 或 reject 的参数;
这个过程有点类似于发布订阅者模式:使用 then 来注册事件,那什么时候来通知这些事件是否执行呢?就是在 resolve 方法执行或者 reject 方法执行时。
class PromiseAPlus {
// 三种状态
static PENDING = 'pending'
static RESOLVED = 'resolved'
static REJECTED = 'reject'
constructor(executor) {
this.status = PENDING // 初始状态为 pending
this.value = undefined // 存储 this._resolve 即操作成功 返回的值
this.reason = undefined // 存储 this._reject 即操作失败 返回的值
this.callbacks = [] // 同一个 Promise 的 then 方法可以调用多次
executor(this._resolve.bind(this), this._reject.bind(this));
}
// 成功的回调
_resolve (value) {
this.resultValue = value
this.status = RESOLVED
// 通知事件执行
this.callbacks.forEach((cb) => this._handler(cb));
}
// 失败的回调
_reject (reason) {
this.reason = reason
this.status = REJECTED
// 通知事件执行
this.callbacks.forEach((cb) => this._handler(cb));
}
// onFulfilled 是成功时执行的函数
// onRejected 是失败时执行的函数
then (onFulfilled, onRejected) {
// 这里可以理解为在注册事件
// 也就是将需要执行的回调函数存储起来
this.callbacks.push({
onFulfilled,
onRejected
})
}
_handler (callback) {
const { onFulfilled, onRejected } = callback;
if (this.status === PromiseAPlus.RESOLVED && onFulfilled) {
// 传入存储的值
onFulfilled(this.value);
}
if (this.status === PromiseAPlus.REJECTED && onRejected) {
// 传入存储的错误信息
onRejected(this.reason);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
重难点:then 方法的链式调用。
其实链式调用无非就是再返回一个类的实例,但是不能直接返回 this,而是要返回一个新的 Promise。值得注意的是,then 函数中返回的 Promise 的 value 值来源于当前 then 函数的 onFulfilled 函数(第一个参数)的执行结果。
class PromiseAPlus {
...
// onFulfilled 是成功时执行的函数
// onRejected 是失败时执行的函数
then (onFulfilled, onRejected) {
// 这里可以理解为在注册事件
// 也就是将需要执行的回调函数存储起来
return new PromiseAPlus((nextResolve, nextReject) => {
this._handler({
nextResolve,
nextReject,
onFulfilled,
onRejected
})
})
}
_handler (callback) {
const { onFulfilled, onRejected, nextResolve, nextReject } = callback
if (this.status === PromiseAPlus.pending) {
this.callbacks.push(callback)
return
}
// 传入存储的值
// 未传入 onFulfilled 时,将 undefined 传入
if (this.status === PromiseAPlus.RESOLVED) {
const nextValue = onFulfilled ? onFulfilled(this.value) : undefined
nextResolve(nextValue)
return
}
// 传入存储的值
// 未传入 onFulfilled 时,将 undefined 传入
if (this.status === PromiseAPlus.REJECTED) {
const nextReason = onRejected ? onRejected(this.reason) : undefined
nextResolve(nextReason)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# async / await
async/await 其实是 Generator 的语法糖,它能实现的效果都能用 then 链来实现,目的是为了优化 then 链,以同步的形式来写异步逻辑。顾名思义,async 用于声明一个方法是异步的,而 await 用于等待一个异步方法执行完成。
async 函数可能包含 0 个或者多个 await 表达式。await 表达式会暂停整个 async 函数的执行进程并出让其控制权,只有当其等待的基于 promise 的异步操作被兑现或被拒绝之后才会恢复进程。promise 的解决值会被当作该 await 表达式的返回值。使用 async / await 关键字就可以在异步代码中使用普通的 try / catch 代码块。
async 函数会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。没有返回值的时候,它会返回 Promise.resolve(undefined)。
对比 Promise 的优势
- 代码更接近于同步代码的写法,
- 可以更优雅的传递中间值
- 错误处理更友好,可以使用 try/catch
- 更友好的调试,调试器只能追踪同步代码,无法进入 then 内部