My Little World

关于promise

promise

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

简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var promise = new Promise(function(resolve, reject) {
// ... some code

if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});

promise
.then(function(value) { //resolve(value);回调函数
// success
}, function(error) { // reject(error);回调函数
// failure
})
.catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});

1、Promise对象是一个构造函数,用来生成Promise实例,
2、Promise构造函数的参数是一个函数,该函数有两个参数,分别是两个函数:resolve和 reject
3、resolve函数在promise对象状态从Pending变为Fulfiled时调用,即异步操作成功的时候调用,参数一般为获取的结果,方便回调函数使用,或者另一个promise实例,继续进行回调
reject函数在promise对象状态从Pending变为Rejected时调用,即异步操作失败的时候调用,参数一般为错误Error对象,报出错误
4、Promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数
5、then方法有两个参数,均为匿名函数,第一个匿名函数为resolve()的定义,第二个参数为reject()的定义
6、Promise对象状态变为Resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为Rejected,就会调用catch方法指定的回调函数,处理这个错误。
另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。
注意,如果then方法定义了reject(),将不会再调用catch方法,如果then里面没有reject,发生错误时将会调用catch

执行流程

1.then方法会在与promise同步的任务完成之后再执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});

promise.then(function() {
console.log('Resolved.');
});

console.log('Hi!');
//打印顺序
"Promise"
"Hi!"
"Resolved."

Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以Resolved最后输出。

2、如果Promise1的resolved返回另一个promise2,那Promise1的then会根据promise2的状态决定执行reject还是resolved

1
2
3
4
5
6
7
8
9
10
11
12
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})

var p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})

p2
.then(result => console.log(result))
.catch(error => console.log(error))
// Error: fail

上面代码中,p1是一个Promise,3秒之后变为rejected。p2的状态在1秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了2秒,p1变为rejected,导致触发catch方法指定的回调函数。

3、在Promise构造函数的参数函数里,在调用resolve()或reject()之后,仍会执行后续语句,但如果是抛错语句将不会执行,同样在抛错语句之后的resolve()调用也不会被执行

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
var promise = new Promise(function(resolve, reject) {
resolve('ok');
console.log('1111')
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log('报错啦') });
//1111
//ok
//因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务,所以会先打印1111,,再打印ok

var promise = new Promise(function(resolve, reject) {
return resolve('ok');
console.log('1111')
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log('报错啦') });
//ok
//return 方法阻止继续执行后续操作

var promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log('报错啦') });
//ok

var promise = new Promise(function(resolve, reject) {
throw new Error('test');
resolve('ok');

});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log('报错啦') });
//报错啦

4、then方法会返回一个promise对象,因此可以继续在then函数后面加then函数,这时前面then函数应该会return一个结果值作为后面then函数的参数,
前面then函数如果执行resolve()则后面then函数也会执行resolve(),前面then函数如果执行reject()则后面then函数也会执行reject(),
但如果前面then函数return一个promise对象,那后面的then函数将会根据这个promise的执行结果去执行resolve()还是reject()

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
var promise = new Promise(function(resolve, reject){
resolve(123)
});
promise.then(function(json) {
console.log('Contents: ' + json);
return 1223;
}, function(error) {
console.error('出错了', error);
return '2423'
})
.then(function(val){
console.log(val);
},function(val){
console.log(val)
});
//"Contents: 123"
//1223

var promise = new Promise(function(resolve, reject){
reject(456)
});
promise.then(function(json) {
console.log('Contents: ' + json);
return 1223;
}, function(val,error) {
console.log(val);
console.error('出错了', error);
return '2423'
})
.then(function(val){
console.log(val);
},function(val){
console.log(val)
});

//456
//"出错了"
//"2423"

var promise = new Promise(function(resolve, reject){
// resolve(123)
reject(456)
});
var promise1 = new Promise(function(resolve, reject){
resolve(789)
});
promise.then(function(json) {
console.log('Contents: ' + json);
return 1223;
}, function(val,error) {
console.log(val);
console.error('出错了', error);
return promise1
})
.then(function(val){
console.log(111+val);
},function(val){
console.log(222+val)
});

//456
//"出错了"
//900

then 方法链式调用箭头函数格式

1
2
3
4
5
6
promise.then(
param1 => {}
).then(
param2 => {},
err => {}
);

5、promise 如果发生了错误,无论reject()或者catch在哪一层,会一直向后传递,直到被捕获为止,即遇到reject()或者catch就会抛出来,如果后续所有回调函数中都没有reject()或者catch,错误就不会被抛出来
catch方法会返回一个promise,所以可以继续写then(),catch()抛完错之后会继续执行后面这个then()
catch()里面还可以再抛错,如果catch后面没有reject()或者catch(),错误将不会被抛出来
如果catch之前的promise没有遇到错误,catch之后又有then(),则执行流程会跳过catch,继续执行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
29
30
31
32
33
34
35
36
var promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise
.then(function(value) { console.log(value); return '2'}, function() { //捕获test
throw new Error('test1');
})
.then(function(value) { console.log(value);return '3' })
.catch(function(error) { console.log(error);return '4'}) //捕获test1
.then(function(value) { console.log(value); }) //4


var promise = new Promise(function(resolve, reject) {
resolve('1')
});
promise
.then(function(value) { console.log(value); return '2'}, function() { //1
throw new Error('test1');
})
.then(function(value) { console.log(value);return '3' })//2
.catch(function(error) { console.log(error) return '4'})
.then(function(value) { console.log(value); })//3 没遇到错误直接跳过来

var promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise
.then(function(value) { console.log(value); return '2'}, function(error) { //捕获test
console.log(error)
throw new Error('test1');
})
.then(function(value) { console.log(value);return '3' })
.catch(function(error) { console.log(error);throw new Error('test2'); return '4'}) //捕获test1
.then(function(value) { console.log(value); },function(error){//捕获test2
console.log(error)
})

6.promise resolve return err 并不会被catch 或者reject捕获,会将错误以参数形式传给then的resolve回调函数

1
2
3
4
5
6
7
8
9
10
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res) //打印出err
})
.catch((err) => {
console.log('catch: ', err)
})

then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环

1
2
3
4
5
6
7
const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(console.error)

//抛错

.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透

1
2
3
4
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log) ///打印1

API

Promise.all

用于将多个 Promise 实例,包装成一个新的 Promise 实例
var p = Promise.all([p1, p2, p3])
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race

将多个Promise实例,包装成一个新的Promise实例
var p = Promise.race([p1, p2, p3]);
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

Promise.resolve

将现有对象转为Promise对象
var Promise = Promise.resolve(参数);

Promise.reject

返回一个新的 Promise 实例,该实例的状态为rejected。
var p = Promise.reject(‘出错了’);
Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数

done finally

done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误,没有参数
finally方法用于指定不管Promise对象最后状态如何,都会执行的操作
可以接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。