0%

Promise学习

Promise的基础知识

Promise相当于异步操作结果的占位符,异步操作返回一个Promise,比如:

1
2
let promise = readFile("example.txt");
//readFile承诺将在未来的某个时刻完成

接下来就是对promise进行处理

Promise的生命周期

每个Promise都有一个生命周期,整个生命周期一共有两个状态:进行中(pending)和已处理(settled)。其中settled会有两种可选状态:成功(fulfilled)和失败(rejected)。

用上面的例子来举例,readFile函数返回一个Promise给promise变量,这是还未开始读取文件,Promise就处于pending状态。读取文件结束后Promise就会进入到settled状态中的其中一种状态。

  • Fulfilled Promise异步操作成功完成
  • Rejected 由于程序错误或一些其他原因,Promise异步操作未能成功完成

Promise状态改变时通过调用then()方法和catch()方法来传递相应的处理函数;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
promise.then(function(contents){
//处理完成的数据
}, function(err){
//拒绝
});

//未处理失败情况
promise.then(function(contents){
console.log(contents);
});

//未处理成功情况
promise.then(null, function(err){
console.log(err);
});

//处理失败情况
promise.catch(function(err){
console.log(err);
});

then()方法和catch方法一起使用能更好的处理异步操作结果,这套体系能够清楚地指明操作结果是成功还是失败。

Promise构造函数

构造函数接受一个参数,这个参数叫做Promise的执行器,执行器是一个函数,这个函数传入两个参数,一个resolve()函数,一个reject()函数

示例代码来自书本《深入理解ES6》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
let fs = require("fs");

function readFile(filename){
return new Promise(function(resolve, reject){

//触发异步操作
fs.readFile(filname, {encoding: "utf8"}, function(err, contents){

//检查是否有错误
if(err){
reject(err);
return;
}

//成功读取文件
resolve(contents);
});
});
}

let promise = readFile("example.txt");

promise.then(function(contents){
//完成
console.log(contents);
}, function(err){
//拒绝
console.log(err.message);
});

Promise.resolve()和Promise.reject()

这个函数接受一个参数:

  • 参数为一个确定的值,返回一个只能处理fulfilled状态或rejected状态的Promise;
  • 参数为一个带有then方法的对象,返回一个含有这个then方法的Promise;
  • 参数为一个Promise,不做处理,直接返回这个Promise;
1
2
3
4
5
let promise1 = Promise.resolve(12); //只能处理完成状态

promise1.then(function(value){
console.log(value); //12
});

串联Promise

一个Promise被处理了之后会接着返回另一个Promise,就行串联一样,可以一直处理下来,并且上一级的Promise还能返回值给接下来的Promise处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let p1 = new Promise(function(resolve, reject){
resolve(12);
});

p1.then(function(value){

console.log(value); //12

return value - 2; //传递给下一个Promise

}).then(function(value2){

console.log(value2); //10

throw new Error("Boom!"); //抛出错误

}).catch(function(err){

console.log(err.message); //"Boom!
});

小贴士:务必在Promise链的末尾留一个拒绝处理函数以确保能够正确处理所有可能发生的错误。

被返回的值也可以是一个Promise,这时接下来的函数就是处理这个Promise。

响应多个Promise

使用Promise.all()和Promise.race()两个方法来监听多个Promise。

Promise.all()

方法接受一个参数,这个参数是个含有多个受监视Promise的可迭代对象(比如:数组,Set,Map,字符串);返回一个Promise。

只有当参数中所有Promise都被解决,返回的Promise才会被解决。传入所有Promise的完成值数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let p1 = new Promise(function(resolve, reject){
resolve(200);
});
let p2 = new Promise(function(resolve, reject){
resolve(201);
});
let p3 = new Promise(function(resolve, reject){
resolve(202);
});

let p4 = Promise.all([p1,p2,p3]);

p4.then(function(valueArr){
console.log(Array.isArray(valueArr)); //true
console.log(valueArr[0]); //200
console.log(valueArr[1]); //201
console.log(valueArr[2]); //202
});

当转入Promise中有一个被拒绝,则返回的Promise被拒绝。

1
2
3
4
5
6
7
8
9
10
let p5 = new Promise(function(resolve, reject){
reject(404);
});

let p6 = Promise.all([p1,p2,p3,p5]);

p6.then(function(value){
console.log(Array.isArray(value)); //false
console.log(value); //404
});

Promise.race()

这个方法与Promise.all()方法接受的参数相同,也返回一个Promise。但是这个方法是,只要传入Promise中有一个被解决,返回的Promise状态就为被解决。

实际上,传给Promise.race()方法的Promise会进行竞选,以决出哪个最先被解决,如果最先被解决的是已完成Promise,则返回已完成Promise;如果先解决的是已拒绝的Promise,则返回已拒绝Promise。

1
2
3
4
5
6
let p7 = Promise.race([p1,p2,p3]);

p7.then(function(value){
例子中没有真正的异步,在真实异步操作过程中,这里的value值是最先解决的Promise接收到的值;
console.log(value); //200
});