Promise对象

jquery的ajax返回的是deferred对象,通过promise的resolve()方法将其转换为promise对象。

promise含义

1.Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
2.Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就固定,不会再变了,会一直保持这个结果。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
const promise = new Promise((resolve, reject) => {
console.log('Promise');
() {
resolve(value);
} else {
reject(error);
}
});
promise.then(value => {
// success
},error => {
// failure
});

1.promise的构造函数接受一个函数作为参数,这个函数有两个参数分别是resolve和reject。而resolve和reject又各自是两个函数。
resolve函数,当Promise对象的状态从 pending 变为 resolved,在异步操作成功时调用,并将异步操作的结果作为参数value传递出去。
reject函数,当Promise对象的状态从pending 变为 rejected,在异步操作失败时调用,并将异步操作报出的错误value,作为参数传递出去。
2.then方法的参数是两个回调函数:
第一个回调函数是promise对象的状态变为resolved时调用,第二个回调函数(可选)是Promise对象的状态变为rejected时调用。第二个参数是可选的。
then可以采用链式写法。
3.Promise 新建后就会立即执行。即回立马输出Promise。
4.Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

resolve的参数是promise对象时:

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

const 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方法指定的回调函数。

Promise.prototype.finally():

1
2
3
4
Promise
.then(result => {})
.catch(error => {})
.finally(() => {})

不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

Promise.all():

1
var p =Promise.all([p1,p2,p3]);

p的状态由p1、p2、p3决定,分为两种情况。
当该数组里的所有Promise实例都进入Fulfilled状态,Promise.all返回的实例才会变成Fulfilled状态。并将Promise实例数组的所有返回值组成一个数组,传递给Promise.all返回实例的回调函数。
当该数组里的某个Promise实例都进入Rejected状态,Promise.all返回的实例会立即变成Rejected状态。并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。

Promise.race():

1
var p =Promise.race([p1,p2,p3]);

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.resolve():

1
var jsPromise = Promise.resolve($.ajax('/whatever.json'));

上面代码将 jQuery 生成的deferred对象,转为一个新的 Promise 对象

Promise.resolve(‘foo’); <==> new Promise(resolve => resolve(‘foo’));

构造函数和原型上的方法

1.
Promise.prototype.then(),Promise.prototype.catch(),Promise.prototype.finally();
Promise.all(),Promise.race(),Promise.resolve(),Promise.reject(),Promise.try();

2.在Promise构造函数上实现的all,race,reject,resolve,不能在对象的实例中访问,属于Promise构造函数自己,这样做保证了对象的命名空间整洁。所以这几个函数的调用方式是Promise.all(),Promise.race(),Promise.reject(),Promise.resolve()。

3.在构造函数原型上实现then,catch的方法是为了让Promise构造函数创建的实例共享then,catch方法。

例子

1.异步加载图片

1
2
3
4
5
6
7
8
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = () => reject(new Error('图片加载失败'));
image.src = url;
});
}

2.Promise的then方法的参数期望是函数,传入非函数则会发生值穿透。

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

3.实现一个简单的promise
https://segmentfault.com/a/1190000009792439

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
function MyPromise(fn) {
this._status = 'pending';
this._value = undefined;
this._onResolvedCallback = [];
this._onRejectCallback = [];
fn(resolve.bind(this), reject.bind(this));
}
function resolve(value) {
if(this._status === 'pending') {
this._status = 'resolved';
this._value = value;
var fn;
while(fn = this._onResolvedCallback.pop()) {
fn.call(this, value);
}
}
}
function reject(reason) {
if(this._status === 'pending') {
this._status = 'reject';
this._value = reason;
var fn;
while(fn = this._onRejectedCallback.pop()) {
fn.call(this, value);
}
}
}
MyPromise.prototype.then = function(onResolved, onRejected) {
var self = this;
var promise2;
onResolved = typeof onResolved === 'function' ? onResolved : function(v) {};
onRejected = typeof onRejected === 'function' ? onRejected : function (r) {};
if(self._status === 'resolved') {
return promise = new MyPromise(function(resolve, reject) {
try{
var x = onResolved(self._value);
if(x instanceof MyPromise) {
x.then(resolve, reject);
}
resolve(x);
} catch(e) {
reject(e);
}
});
}
if (self._status === 'rejected') {
return promise2 = new MyPromise (function (resolve, reject) {
try {
var x = onRejected(self._value)
if (x instanceof MyPromise) {
x.then(resolve,reject)
}
} catch(e) {
reject(e)
}
})
}
if(self._status === 'pending') {
return promise2 = new MyPromise (function (resolve, reject) {
self._onResolvedCallback.push(function (value) {
try{
var x = onResolved(self._value)
if (x instanceof MyPromise) {
x.then(resolve, reject)
}
} catch (e) {
reject(e)
}
})
self._onRejectCallback.push(function(reason) {
try {
var x =onRejected(self._value)
if(x instanceof Promise) {
x.then(resolve, reject)
}
resolve(x)
} catch (e) {
reject(e)
}
})
})
}
}
//test code
var myFirstPromise = new MyPromise(function(resolve, reject){
setTimeout(function(){
resolve("成功!"); //代码正常执行!
}, 1000);
});
myFirstPromise.then(function (successMessage) {
console.log("Yay! " + successMessage);
})