Promise学习

Promise的状态

Promise有三个状态:

  1. pending:[待定]初始状态
  2. fulfilled:[实现]操作成功
  3. rejected:[被否决]操作失败

promise状态发生改变,就会触发then()里的响应函数处理后续步骤。
promise状态一经改变,不会再变。

Promise对象的状态改变,只有两种可能:

  1. pending变为fulfilled
  2. pending变为rejected

这两种情况只要发生,状态就凝固了,不会再变了。


基本使用

知识点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let p = new Promise((res, rej) => {
let t = new Date(),
s = t.getSeconds();
if(s % 2) {
res(s);
}else{
rej(s, "参数二");
}
});

# 调用方式1
p.then(res => console.log(res, "成功"))
.catch(err => console.log(err, "失败"));
# 调用方式2
p.then(
res => console.log(res, "成功"),
err => console.log(err, "失败")
);

这里的rej回调可以放在catch(调用方式1),也可以放在then的第二个参数(调用方式2)。
当然如果两个同时使用(调用方式3),只会执行放在.then的第二个参数的函数,catch内的函数不会执行。
通常都是使用调用方式1的用法。

奇怪的想法

返回多个参数会怎么样?

1
2
3
4
5
6
7
8
9
10
11
12
13
let p = new Promise((res, rej) => {
let t = new Date(),
s = t.getSeconds();
if(s % 2) {
res(s, "参数二");
}else{
rej(s, "失败参数2");
}
});

// 调用方式1
p.then((res, res2) => console.log(res, res2, "成功"))
.catch((err, err2) => console.log(err, err2, "失败"));

小结:假如向res或者rej函数中传入两个以上的参数,在响应函数当中只能取到第一个参数。

假如.then()上面两种调用方式结合在一起会怎么样?

1
2
3
4
5
6
7
// 调用方式3

p.then(
(res, res2) => console.log(res, res2, "成功"),
(err, err2) => console.log(err, err2, "失败")
)
.catch(err => console.log(err, "失败2"));

小结:Promiserejected状态下,.then()内有第二个参数,并且后续紧跟.catch()。只会执行.then()内第二个参数的响应函数。

链式调用

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
function getImage(imgSrc) {
return new Promise((res, rej) => {
let img = new Image();
img.onload = function () {
res(img.src);
}

img.onerror = function () {
rej(`图片加载失败:${imgSrc}`);
}

img.src = imgSrc;
});
}

getImage("image/1.png")
.then(src => {
console.log(src);
return getImage("image/2.png");
})
.then(src => {
console.log(src);
return getImage("image/3.png");
})
.then(src => {
console.log(src);
})
.catch(err => console.log(err));

通过返回一个Promise实例来实现链式调用。(使用方式跟原理有点像jQuery)

在上面代码中,假如有其中一张图片不存在,那么就会直接跑catch内的函数。
当1.png这个图片不存在,却还想继续加载图片时,可以改写成这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
getImage("image/4.png")
.then(src => {
console.log(src);
return getImage("image/4.png");
}, err => {
console.log(err);
return getImage("image/4.png");
})
.then(src => {
console.log(src);
return getImage("image/5.png");
}, err => {
console.log(err);
return getImage("image/6.png");
})
.then(src => {
console.log(src);
})
.catch(err => console.log(err));

使用调用方式2去接收错误错误,并且返回Promise实例。让后续请求继续执行。
大概结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
// 方法一
promise对象
.then(成功回调, 失败回调)
.then(成功回调, 失败回调)
.then(成功回调, 失败回调)

// 方法二
promise对象
.then(成功回调, 失败回调)
.then(成功回调, 失败回调)
.then(成功回调)
.catch(失败回调)

奇怪的想法

假如链式调用中不返回Promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
getImage("image/1.png")
.then(src => console.log(src)) // http://127.0.0.1:5500/face/2/image/1.png
.then(src => console.log(src)) // undefined
.then(src => console.log(src)) // undefined
.catch(err => console.log(err));

getImage("image/不存在的.png")
.then(
src => console.log(src),
err => console.log(err) // 图片加载失败:image/不存在的.png
)
.then(
src => {
console.log(src); // undefined
return 666;
},
err => console.log(err)
)
.then(
src => console.log(src), // 666
err => console.log(err)
);

小结:不返回Promise的时候,后续.then()的响应函数也会继续执行。只不过返回给响应函数的返回值是根据上一个.then中的返回值来决定的。
也就说明了.then()会返回一个Promise实例,所以他可以继续进行链式调用。
且这个实例的状态是fulfilled成功的。

.then().catch()中,假如没有返回Promise实例

  1. 会自动返回一个状态为fulfilledPromise实例
  2. 且马上执行后面的.then()
  3. 后面.then()中参数的值,上一个.then()函数的返回值。

.then().catch()中,假如返回Promise实例

  1. 会根据返回的Promise实例状态,去执行对应的响应函数

抛出异常会怎么样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
getImage("image/1.png")
.then(src => {
console.log(src); // http://127.0.0.1:5500/face/2/image/1.png
throw new Error("err");
})
.then(res => console.log(res))
.catch(err => console.log(err)) // Error: err
.then(res => {
console.log(res); // undefined
throw new Error("err2");
})
.then(
res => console.log(res),
err => console.log(err) // Error: err2
)
.catch(err => console.log(err));

小结:上面代码中,抛出异常都会走到最近的reject响应函数当中,并且跳过他们之间的.then()响应函数。


参考链接:https://www.jianshu.com/p/1b63a13c2701



Promise学习
作者
墨陌默
发布于
2020年9月7日
许可协议