Promise
# Promise
# Promise 简介
Promise 是一种处理异步代码的方式,支持链式调用,可以解决回调地狱问题。
jQuery 回调地狱写法
// 一个异步事件要依赖另一个异步事件的返回值
// 可以发现每个异步请求是在函数里面一层一层嵌套的
function ajax1() {
$.ajax({
type: 'POST',
url: '',
data: {},
dataType: 'json',
success: function(res) {
ajax2(res.data)
}
})
}
function ajax2(data) {
$.ajax({
type: 'POST',
url: '',
data: data,
dataType: 'json',
success: function (res) {
ajax3(res.data)
}
})
}
function ajax3(data) {
$.ajax({
type: 'POST',
url: '',
data: data,
dataType: 'json',
success: function (res) {
console.log(res)
}
})
}
// 运行
ajax1()
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
Promise 链式调用写法
// Promise 是支持链式调用的
// 使用方法是将 Promise 封装, 每次在 then 中执行完毕后返回一个新的 Promise
const ajax1 = new Promise(function (resolve,reject) {
$.ajax({
type: 'POST',
url: '',
data: {},
dataType: 'json',
success: function (res) {
resolve(res.data)
}
})
})
function ajax2 (data) {
return new Promise(function (resolve,reject) {
$.ajax({
type: 'POST',
url: '',
data: data,
dataType: 'json',
success: function (res) {
resolve(res.data)
}
})
})
}
function ajax3 (data) {
return new Promise(function (resolve,reject) {
$.ajax({
type: 'POST',
url: '',
data: data,
dataType: 'json',
success: function (res) {
resolve(res.data)
}
})
})
}
// 运行
ajax1.then(function (data) {
return ajax2(data)
}).then(function (data) {
return ajax3(data)
})
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
Promise 对象有三种状态:pending(等待中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
一个 Promise 必然处于以下几种状态之一:
- 等待中(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已成功(fulfilled):意味着操作成功。
- 已拒绝(rejected):意味着操作失败。
# 基本语法
创建 Promise 实例:
const promise = new Promise(function(resolve, reject) {
// ... some code
if ( /* 异步操作成功 */ ) {
resolve(value)
} else {
reject(error)
}
})
2
3
4
5
6
7
8
9
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve
和 reject
,它们都是函数类型,由 JavaScript 引擎提供,不用自己实现。
- 处理结果正常的话,调用
resolve(处理结果值)
,将 Promise 对象的状态从「等待中」变为「成功」(即从 pending 变为 fulfilled)。该函数在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。 - 处理结果错误的话,调用
reject(错误信息)
,将 Promise 对象的状态从「等待中」变为「失败」(即从 pending 变为 rejected)。该函数在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise 内部的状态(pending、fulfilled、rejected)走向如下图所示:
(Promise 状态的走向)
# Promise.prototype.then()
基本语法
promise.then(onFulfilled, onRejected)
Promise 实例生成以后,可以用 then
方法指定 fulfilled 状态和 rejected 状态的回调函数。该方法的第一个参数又名 onFulfilled,第二个参数又名 onRejected,都应是函数类型。
promise.then(function(value) {
// success
}, function(error) {
// failure
})
2
3
4
5
示例
let p1 = new Promise((resolve, reject) => {
resolve('p1 成功')
reject('p1 失败')
})
let p2 = new Promise((resolve, reject) => {
reject('p2 失败')
resolve('p2 成功')
})
let p3 = new Promise((resolve, reject) => {
throw('p3 报错')
})
p1.then(value => {
console.log(value)
}, error => {
console.log(error)
})
p2.then(value => {
console.log(value)
}, error => {
console.log(error)
})
p3.then(value => {
console.log(value)
}, error => {
console.log(error)
})
// "p1 成功"
// "p2 失败"
// "p3 报错"
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
这里包含了四个知识点:
- 执行了
resolve
,Promise 状态会变成fulfilled
,即「已完成状态」。 - 执行了
reject
,Promise 状态会变成rejected
,即「被拒绝状态」。 - Promise 状态的改变不可逆,第一次成功就永久为
fulfilled
,第一次失败就永久为rejected
。 - Promise 中有
throw
的话,就相当于执行了reject
。
# Promise.prototype.catch()
可以使用 Promise 对象的 catch
方法来捕获异步操作过程中出现的任何异常。
基本语法
p.catch(onRejected)
p.catch(function(reason) { // rejection })
示例
function test() {
return new Promise((resolve, reject) => {
reject(new Error('es'))
})
}
test().catch((e) => {
console.log(e.message) // es
})
2
3
4
5
6
7
8
9
注意
虽然都能被 catch
捕获到,但不建议在 Promise 内部使用 throw new Error()
来触发异常,而应该使用 reject(new Error())
的方式来做,因为 throw
的方式并没有改变 Promise 的状态。
# Promise.resolve()
静态方法 Promise.resolve(value)
可以认为是 new Promise()
方法的快捷方式。
比如下面两个写法是等价的:
// 写法一
Promise.resolve(42)
// 写法二
new Promise(function(resolve) {
resolve(42)
})
2
3
4
5
6
7
上面代码中的 resolve(42)
会让这个 Promise 对象立即进入确定(即 fulfilled)状态,并将 42
传递给后面 then
里所指定的 onFulfilled 函数。
方法 Promise.resolve(value)
的返回值也是一个 Promise 对象,所以我们可以像下面那样接着对其返回值进行 .then
调用:
Promise.resolve(42).then(function(value) {
console.log(value)
})
2
3
这种简写方式在进行 Promise 对象的初始化或者编写测试代码的时候都非常方便。
# Promise.reject()
Promise.reject(error)
是和 Promise.resolve(value)
类似的静态方法,是 new Promise()
方法的快捷方式。
下面两个写法是等价的:
// 写法一
Promise.reject(new Error("出错了"))
// 写法二
new Promise(function(resolve, reject) {
reject(new Error('出错了'))
})
2
3
4
5
6
7
这段代码的功能是调用该 Promise 对象通过 .then
指定的 onRejected 函数,并将错误(Error)对象传递给这个 onRejected 函数。
Promise.reject(new Error('BOOM!'))
# Promise.all()
基本语法
Promise.all(promiseArray)
示例
var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then(function(results) {
console.log(results) // [1, 2, 3]
})
2
3
4
5
6
Promise.all()
生成并返回一个新的 Promise 对象,所以它可以使用 Promise 实例的所有方法。参数传递 promise 数组中所有的 Promise 对象都变为 resolve
的时候,该方法才会返回,新创建的 Promise 则会使用这些 promise 的值。
如果参数中的任何一个 promise 为 reject
的话,则整个 Promise.all 调用会立即终止,并返回一个 reject
的新的 Promise 对象。
由于参数数组中的每个元素都是由 Promise.resolve 包装(wrap)的,所以 Promise.all 可以处理不同类型的 Promise 对象。
# Promise.race()
基本语法
Promise.race(promiseArray)
示例
var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
Promise.race([p1, p2, p3]).then(function(value) {
console.log(value) // 1
})
2
3
4
5
6
Promise.race()
生成并返回一个新的 Promise 对象。
参数 promise 数组中的任何一个 Promise 对象如果变为 resolve
或者 reject
的话,该函数就会返回,并使用这个 Promise 对象的值进行 resolve
或者 reject
。
# 参考资料
(完)