0%

js | promise

其实,我对 promise 了解的很差,所以,这篇博文也会继续完善。

在这里,我就以例子为主。


参考资料



回调地狱


promise 设计的一个目的就是解决回调地狱的。

1
2
3
4
5
6
7
8
9
ajaxA(function( ){
ajaxB(function( ){
ajaxC(function( ){
ajaxD(function( ){
......
});
});
});
})

promise 用法


状态

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled): 意味着操作成功完成。
  • 已拒绝(rejected): 意味着操作失败。

状态不可逆转。

因为 Promise.prototype.thenPromise.prototype.catch 方法返回的是 promise, 所以它们可以被链式调用。

案例介绍

链式调用 有 resolve()

1
2
3
4
5
6
7
8
9
10
new Promise(function (resolve, reject) {
console.log(1)
resolve()
}).then(function () {
console.log(2)
}).then(function () {
console.log(3)
})

console.log(777)

输出

1
2
3
4
1
777
2
3

链式调用 无 resolve()

1
2
3
4
5
6
7
8
9
new Promise(function (resolve, reject) {
console.log(1)
}).then(function () {
console.log(2)
}).then(function () {
console.log(3)
})

console.log(777)

输出

1
2
1
777

这里的 resolve 起到的是通知作用。

这其实就是在通知 Promise,当前这个函数结束啦。

你可以开始执行下一个。 这时Promise就会去执行then里面的函数了。

resolve函数, 就好像一个对讲机,当我们的异步任务要结束时,通过对讲机 来通知Promise对象。所以这个resolve函数,必须在异步任务的最后调用(例如ajax的回调方法),相当于告诉Promise对象,该任务结束,请开始下一个。

异步调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
console.log(1)
resolve("XXX")
})
}).then(function (data) {
console.log(data)
}).then(function () {
console.log(2)
}).then(function () {
console.log(3)
// throw "123"
}).then(function () {
console.log(4)
})

console.log(777)

输出

1
2
3
4
5
6
777
1
XXX
2
3
4

这个异步调用很好理解。

异步调用中的异步调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
console.log(1)
resolve("XXX")
})
}).then(function (data) {
axios.get("https://www.baidu.com").then((res) => {
console.log(2)
})
}).then(function () {
console.log(3)
}).then(function () {
console.log(4)
}).then(function () {
console.log(5)
})

console.log(777)

输出

1
2
3
4
5
6
777
1
3
4
5
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
console.log(1)
resolve("XXX")
})
}).then(function (data) {
axios.get("https://www.baidu.com").then((res) => {
console.log(2)
})
}).then(function () {
axios.get("https://www.baidu.com").then((res) => {
console.log(3)
})
}).then(function () {
console.log(4)
}).then(function () {
console.log(5)
})

console.log(777)

输出

1
2
3
4
5
6
777
1
4
5
3
2

之所以是这个顺序,是因为 promise 还涉及到让出线程的概念,这个下面给说。

这里,我想让顺序输出是

1
2
3
4
5
6
777
1
2
3
4
5

可以这样修改

异步调用中的顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
console.log(1)
resolve("XXX")
})
}).then(function (data) {
return new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
console.log(2)
resolve()
})
})
}).then(function () {
axios.get("https://www.baidu.com").then((res) => {
console.log(3)
})
}).then(function () {
console.log(4)
}).then(function () {
console.log(5)
})

console.log(777)

输出

1
2
3
4
5
6
777
1
2
4
5
3

通过上述编写,就可以异步也能同步执行,但是,具体的原理目前还没搞懂。

异常编写

resolve 是成功返回,然后调用成功方法。

reject 是异常返回,然后调用异常捕获方法。

promisethen 中完整版本是

1
2
3
4
5
6
7
p.then(onFulfilled[, onRejected]);

p.then(value => {
// fulfillment
}, reason => {
// rejection
});

即,then 的传入参数是两个方法,其中 第一个是 resolve() 调用,第二个是 reject() 调用。

1
2
3
4
5
6
7
8
9
10
11
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
resolve()
}).catch((reason => {
reject()
}))
}).then((value) => {

}, (reason) => {
console.log(123)
})

输出

1
123

把网关掉,由于没有网络就会调用 reject() 然后触发 then 后面的 onRjected 函数。

1
2
3
4
5
6
7
8
9
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
reject()
})
}).then((value) => {

}, (reason) => {
console.log(123)
})

同样输出

1
123

异常的链式执行

1
2
3
4
5
6
7
8
9
10
11
new Promise(function (resolve, reject) {
axios.get("https://www.baidu.com").then((res) => {
reject()
})
}).then((value) => {

}, (reason) => {
console.log(123)
}).then((value) =>{
console.log(234)
})

输出

1
2
123
234

也就是,执行完 reject 后,依然会正常执行下面的 then。 可以参考上面的图来查看。


其他方法


all

如果我有 A ,B,C 三个异步任务,ABC同时开始执行

A,B,C三个任务全部都结束时,执任务D

传统方法实现起来就比较复杂,Promise就非常简单,就像这样:

1
2
3
4
Promise.all([new Promise(A), new Promise(B), new Promise(C)])
.then(function(){
D();
});

race

那如果我希望 A , B , C 其中任意一个任务完成,

就马上开始任务 D,该怎么做?

1
2
3
4
Promise.race([new Promise(A), new Promise(B), new Promise(C)])
.then(function(){
D();
});

强制顺序同步


第一个例子中

1
2
3
4
5
6
7
8
9
10
new Promise(function (resolve, reject) {
console.log(1)
resolve()
}).then(function () {
console.log(2)
}).then(function () {
console.log(3)
})

console.log(777)

输出

1
2
3
4
1
777
2
3

我如果想执行完 1,2,3 后再执行 777 呢。

那可以借助上面的 all 还有 async/await。

请我喝杯咖啡吧~