什么是Promise
Promise的核心理念是一个异步操作的结果,Promise包含两部分
[[PromiseStates]]
[[PromiseValue]]
Promise状态三种可能:
pending
: 悬而未决resolved
: 决定rejected
: 拒绝
异步性
1
2
3
4
5
6
7
8
9
|
const p = new Promise((resolve, reject) => {
resolve(‘success’);
});
p.then((value) => {
console.log(value);
});
console.log(‘Called first ?’);
|
Promise的then()
具有异步性,当执行到.then()
部分,这部分会自动进入到Promise的异步事件队列,不会阻塞同步代码的执行,所以Called first?
先输出。
输出结果
1
2
|
Called first ?
success
|
立即执行性
1
2
3
4
5
6
7
8
9
10
|
const p = new Promise((resolve, reject) => {
console.log(‘Create a promise’);
resolve(‘success’);
});
p.then((value) => {
console.log(value);
});
console.log(‘After new Promise’);
|
从Promise的异步性,我们可以推断出,After new Promise
,会先于then()
方法中的输出。同时Promise的立即执行性,定义了promise
定义的同时就会立即执行,并不依赖于then()
的调用。而且与函数明显不同,函数需要主动调用才会执行。
输出结果
1
2
3
|
Create a promise
After new Promise
success
|
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
30
31
32
33
34
35
36
37
38
|
const p1 = new Promise((resolve, reject) => {
resolve(1);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 500);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(3);
}, 500);
});
console.log(p1);
console.log(p2);
console.log(p3);
setTimeout(() => {
console.log(‘p2-setTimeout:’, p2);
}, 501);
setTimeout(() => {
console.log(‘p3-setTimeout:’, p3);
}, 501);
p1.then((value) => {
console.log(‘p1-then:’, value);
});
p2.then((value) => {
console.log(‘p2-then:’, value);
});
p3.catch((err) => {
console.log(‘p3-catch’, err);
});
|
当Promise创建完成时,处于 pending 状态;
当Promise执行了resolve
方法,Promise对象的状态会变成 resolved 状态;
当Promise执行了reject
方法,Promise对象的状态会变成 rejected 状态;
先输出
1
2
3
|
Promise {[[PromiseStatus]]: “resolved”, [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: “pending”, [[PromiseValue]]: undefined}
Promise {[[PromiseStatus]]: “pending”, [[PromiseValue]]: undefined}
|
然后输出
1
|
p1-then: 1
|
500ms之后,p2
和p3
的Promise状态被执行,then
被触发,输出:
1
2
|
p2-then: 2
p3-catch 3
|
最后会输出:
1
2
|
p2-setTimeout: Promise {[[PromiseStatus]]: “resolved”, [[PromiseValue]]: 2}
p3-setTimeout: Promise {[[PromiseStatus]]: “rejected”, [[PromiseValue]]: 3}
|
状态不可逆性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
const p1 = new Promise((resolve, reject) => {
resolve(‘p1 success 1’);
resolve(‘p1 success 2’);
});
const p2 = new Promise((resolve, reject) => {
resolve(‘p2 success’);
reject(‘p2 reject’);
});
p1.then((value) => {
console.log(value);
});
p2.then((value) => {
console.log(value);
}, (err) => {
console.log(err);
});
|
Promise一旦变成resolved
或是rejected
,这个状态就不能再次变化,这就是Promise的不可逆性。
输出
1
2
|
p1 success 1
p2 success
|
链式调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
const p = new Promise(((resolve, reject) => {
resolve(1);
}));
p.then((value) => {
console.log(value);
return value * 2;
}).then((value) => {
console.log(value);
}).then((value) => {
console.log(value);
return Promise.resolve(‘resolve’);
}).then((value) => {
console.log(value);
return Promise.reject(‘reject’);
}).then((value) => {
console.log(‘resolve: ‘, value);
}, (err) => {
console.log(‘reject: ‘, err);
});
|
Jquery对象链式调用是执行jquery
方法之后,会继续返回jquery
对象;类似这个原理,Promise对象的then
方法会返回一个新的Promise对象
,这样就可以继续调用then
方法。同样then
方法中的两个参数还是fulfilled
对象和rejected
对象。
当return
一个值或者Promise.resolve()
时,状态为 resolved
当throw
一个异常或者return
Promise.reject()
,状态为 rejected
注: 当then()
方法中没有return
时,会默认返回undefined
,状态为 resolved
输出
1
2
3
4
5
|
1
2
undefined
resolve
reject: reject
|
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
30
31
32
33
34
|
const p1 = new Promise((resolve, reject) => {
foo.bar();
resolve(1);
});
p1.then((value) => {
console.log(‘p1 then value: ‘, value);
}, (err) => {
console.log(‘p1 then err: ‘, err);
}).then((value) => {
console.log(‘p1 then then value: ‘, value);
}, (err) => {
console.log(‘p1 then then err: ‘, err);
});
var p2 = new Promise((resolve, reject) => {
resolve(2);
});
p2.then((value) => {
console.log(‘p2 then value: ‘, value);
foo.bar();
}, (err) => {
console.log(‘p2 then err: ‘, err);
}).then((value) => {
console.log(‘p2 then then value: ‘, value);
}, (err) => {
console.log(‘p2 then then err: ‘, err);
return 1;
}).then((value) => {
console.log(‘p2 then then then value: ‘, value);
}, (err) => {
console.log(‘p2 then then then err: ‘, err);
});
|
Promise中的异常会交给then
方法中的第二个回调函数处理,一旦处理完成,会继续返回一个Promise
对象给后续then
方法。
可以看到输出是p1
和p2
交替输出的,这个并不一定是交替输出,取决于执行情况,也可能是p2
先输出。
输出
1
2
3
4
5
|
p1 then err: ReferenceError: foo is not defined
p2 then value: 2
p1 then then value: undefined
p2 then then err: ReferenceError: foo is not defined
p2 then then then value: 1
|
Promise.resolve()
Promise.resolve()
语法:
1
|
Promise.resolve(value);
|
value
: 用来解析待返回promise
对象的参数,既可以是一个promise
对象,也可以是一个thenable
(即带有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
|
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(p1);
const p3 = new Promise((resolve, reject) => {
resolve(1);
});
const p4 = new Promise((resolve, reject) => {
resolve(p1);
});
// console.log(p1);
// console.log(p2);
// console.log(p3);
// console.log(p4);
console.log(p1 === p2);
console.log(p1 === p3);
console.log(p1 === p4);
console.log(p3 === p4);
p4.then((value) => {
console.log(‘p4 = ‘, value);
});
p2.then((value) => {
console.log(‘p2 = ‘, value);
});
p1.then((value) => {
console.log(‘p1 = ‘, value);
})
|
p1
: 接收了一个普通值1
,所以会返回一个resolved
状态的Promise对象,并且值为1
。
p2
: 接收了一个promise对象p1
,会直接返回这个promise对象。
p3
和p4
: 通过new
方式创建了一个新的promise对象。
所以,p1 === p2
,p3
和p4
都是创建的新对象,所以自身和其他三个对象都不相等。
输出
1234 truefalsefalsefalse
但是后三个输出是:
1
2
3
|
p2 = 1
p1 = 1
p4 = 1
|
很有意思的是,明明是p4
先执行的then
方法,但是却是后输出的。
在定义完4个promise对象时,状态分别为:
1
2
3
4
|
Promise {[[PromiseStatus]]: “resolved”, [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: “resolved”, [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: “resolved”, [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: “pending”, [[PromiseValue]]: undefined}
|
很明显,p4
是pending
状态,与其他三个不同,因为p4
的resolve
中接收的参数是一个promise对象p1
,resolve
会对p1
进行“拆箱”操作,这个过程是异步的。
注:把基本数据类型转换为对应的引用类型的操作称为装箱,把引用类型转换为基本的数据类型称为拆箱。
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
|
const p1 = new Promise((resolve, reject) => {
resolve(Promise.resolve(‘resolve’));
});
const p2 = new Promise((resolve, reject) => {
resolve(Promise.reject(‘reject’));
});
const p3 = new Promise((resolve, reject) => {
reject(Promise.resolve(‘resolve’));
});
p1.then((value) => {
console.log(‘p1-resolve:’, value);
}, (err) => {
console.log(‘p1-reject:’, err);
});
p2.then((value) => {
console.log(‘p2-resolve:’, value);
}, (err) => {
console.log(‘p2-reject:’, err);
});
p3.then((value) => {
console.log(‘p3-resolve:’, value);
}, (err) => {
console.log(‘p3-reject:’, err);
});
|
resolve
方法和reject
方法除了在状态上有区别,处理方式上也有区别,resolve
方法上面提到了会对promise对象“拆箱”,但是reject
方法不会。
p3
没有“拆箱”操作,所以会最先输出,直接调用reject
方法,输出Promise.resolve('resolve')
对象
p1
会“拆箱”得到Promise.resolve('resolve')
这个promise对象的状态和值,调用resolve
方法。
p2
会“拆箱”得到Promise.reject('reject')
这个promise对象的状态和值,因为得到的状态是rejected
,所以会调用reject
方法。
输出
1
2
3
|
p3-reject: Promise {[[PromiseStatus]]: “resolved”, [[PromiseValue]]: “resolve”}
p1-resolve: resolve
p2-reject: reject
|
all() & race() & then() 区别
Promise.all()
语法:
1
|
Promise.all(iterable);
|
Promise.race()
语法:
1
|
Promise.race(iterable)
|
iterable
: 可迭代对象,例如一个数组。
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
|
let timerPromisefy = (delay) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(delay);
}, delay);
});
}
let timerPromisefyReject = (delay) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(delay);
}, delay);
});
}
console.time(‘Promise all’);
Promise.all([
timerPromisefy(1),
timerPromisefy(7),
timerPromisefy(10),
timerPromisefy(9)
]).then((value) => {
console.timeEnd(‘Promise all’);
});
console.time(‘Promise then’);
timerPromisefy(1).then(() => {
return timerPromisefy(7)
}).then(() => {
return timerPromisefy(10)
}).then(() => {
return timerPromisefy(9)
}).then(() => {
console.timeEnd(‘Promise then’)
});
console.time(‘Promise race’);
Promise.race([
timerPromisefy(1),
timerPromisefy(7),
timerPromisefy(10),
timerPromisefy(9)
]).then(value => {
console.timeEnd(‘Promise race’);
});
|
Promise.all()
方法返回一个Promise
,当iterable
参数中的 promise 并行执行,当所有 promise 都已经 resolve 了,返回 resolved 状态。当传递的 promise 包含一个 reject ,则返回 rejected 状态。
如果Promise.all()
返回 resolved , 那么执行时间取决于执行最最慢的那个 promise;如果Promise.all()
返回 rejected , 执行时间取决于第一个返回 rejected 的执行时间。
Promise.race()
方法返回一个Promise
,当iterable
参数中只要有一个 promise 状态被判定了,那么就返回该状态。
所以Promise.race()
的执行时间取决于执行最快的那个 promise。
Promise.then()
方法的执行时间,是每个链式调用总时间之和。
输出
123 Promise race: 2.3232421875msPromise all: 3.675048828125msPromise then: 31.32373046875ms