JavaScript Promise

Promise 是异步编程的一种解决方案。

一、什么是异步编程?

常见的场景是网络请求,网络请求并不能确保立即拿到结果,若是顺序执行,将会等待至网络请求完成后再继续执行,将导致页面运行停滞,出现堵塞,此时便需要异步编程。

异步编程的常见实现方法:

  • 事件监听:监听事件,当事件完成后执行对应方法。

  • 函数回调:传入另一个方法,待请求成功后执行回调方法(callback)。在代码上的实现是嵌套调用的形式,因此在处理大量且复杂的网络请求时会非常麻烦

  • Promise:将嵌套调用改为链式调用,增加了代码的可阅读性和可维护性

二、什么是 Promise?

  • Promise 是异步编程的一种解决方案
  • Promise 将异步执行流程中的网络请求与数据处理进行了分离
  • Promise 将异步操作写成更好理解与维护的链式写法,避免”回调地狱”

三、简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new Promise((resolve, reject) => {
// 异步操作
if (异步操作成功) {
resolve(结果)
} else {
reject(错误信息)
}
}).then(
(结果) => {
// 成功则执行
}
).catch(,
(错误信息) => {
// 失败则执行
}
)

四、链式请求

1
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
new Promise((resolve, reject) => {
// 异步操作1
if (成功) {
resolve(结果1)
} else {
reject(错误信息)
}
}).then(
(res) => {
return new Promise(
(resolve, reject) => {
// 异步操作2
if (成功) {
resolve(结果2)
} else {
reject(错误信息)
}
});
}
).then(
(res) => {
return new Promise(
(resolve, reject) => {
// 异步操作3
if (成功) {
resolve(结果3)
} else {
reject(错误信息)
}
});
}
).then(
(res) => {
return new Promise(
// reject是可选的,这里必然不会失败,因此可以不填入
(resolve) => {
// 数据处理
});
}
).catch(
(错误信息) => {
// 错误处理
}
);

五、三种状态

Promise 有且仅有三种状态:

  • pending:进行中
  • fulfill:成功
  • reject:失败

需要注意的是,Promise 仅会从进行中变为成功/失败,当处于成功/失败时,状态便会固定不再改变。

六、异步操作函数

  • 构造函数接收一个函数作为参数,这里将这个函数称为异步操作函数
  • 异步操作函数接收 resolve 和 reject 两个参数,它们均是回调函数
  • 异步操作函数将会立刻执行
  • 当执行成功时,应调用 resolve 并传入成功信息
  • 当执行失败时,应调用 reject 并传入失败信息

七、Promise 的实例方法

1. then()

可以接收两个函数参数,其中:

  • 参数一在 Promise 成功后被调用

  • 参数二在 Promise 失败后被调用

    可选

2. catch()

可以接收一个函数参数,该函数将在 Promise 失败后被调用。

3. finally()

可以接收一个函数参数,该函数无论 Promise 成功与否都会被调用。

八、Promise.all

1. 说明

用于解决这样的场景:需要同时发送两次网络请求,并等待两次网络请求均成功后,完成相应操作。

该方法可以接收多个 Promise,并且会在所有 Promise 成功后才

2. 语法

1
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
Promise.all([
new Promise((resolve, reject) => {
// 异步操作1
if (成功) {
resolve(结果1)
} else {
reject(错误信息)
}
}),
new Promise((resolve, reject) => {
// 异步操作2
if (成功) {
resolve(结果1)
} else {
reject(错误信息)
}
}),
]).then(
(resolves) => {
// 数据处理
}
).catch(
(错误信息) => {
// 错误信息处理
}
)

两次异步操作所得的结果将放入数组中,通过 resolves[索引] 的方式访问

九、手写一个极简 Promise

1
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
class Promise {
constructor(fun) {
fun(this.resolve.bind(this), this.reject.bind(this))
return this
}
resolve(res) {
if (this.good !== undefined) {
this.good(res)
}
}
reject(err) {
if (this.bad !== undefined) {
this.bad(err)
}
}
then(fun) {
this.good = fun
return this
}
catch(fun) {
this.bad = fun
return this
}
}

new Promise((resolve, reject) => {
setTimeout(() => {
let flag = Math.random() >= 0.5
if (flag) {
resolve(flag)
} else {
reject(flag)
}
}, 2000)
}).then((res) => {
console.log("正确了,结果是:" + res)
}).catch((err) => {
console.log("出错了,错误是:" + err)
})

参考