JavaScript中对Promise对象的理解

  • Post author:
  • Post category:java


注意单词对应的翻译,有助于理解整个模式

  • promise: 承诺

  • pending: 待定

  • settled: 定了

  • resolve(d): (已)解决

  • reject(ed): (已)拒绝

  • onFulfilled: 已履行(事件)

  • onRejected: 已拒绝(事件)

  • then: 然后,接下来

  • catch: 捕获

  • race: 赛跑

  • future: 未来(值)

  • thenable:可then的(有then属性的)

一.Promise是什么

一套异步操作处理机制,

Promise A+

是规范,jQuery、ES2015、q的promise都是对该规范的一种实现

二.Promise有什么特点

  • 更容易控制异步操作的执行顺序

  • 可以在一系列异步操作中,灵活地处理错误

  • 支持链式调用,好写

  • 能够消除回调金字塔,好看

三.Promise有什么用

  • 实现串行任务队列

  • 实现串行任务管道

  • 处理运行时才能确定执行顺序的串行任务

(篇幅限制,具体适用场景以后再展开)

四.Promise类型

内部属性[[PromiseStatus]]/[[PromiseValue]]

[[PromiseStatus]]:pending(待定) | resolved(已解决) | rejected(已拒绝)

后两个统称

settled

(定了),

pending

是初始状态,如果

new Promise(func)

后,

func

中的

resolve



reject

都还没有执行,此时

status=pending

[[PromiseValue]]:undefined | resolve/reject的参数 | Promise.resolve/reject的!thenable参数 | onFulfilled/onRejected的返回值



then

被调用时,该值会被传给

then



onFulfilled



onRejected

,如果

resolve



reject

始终没有执行,那么

then



onFulfilled



onRejected

也始终不会执行

构造器参数resolve/reject

resolve(解决)

执行

resolve

后,触发

then



onFulfilled

回调,并把

resolve

的参数传递给

onFulfilled

reject(拒绝)

执行

reject

后,触发

then

|

catch



onRejected

回调,并把

reject

的参数传递给

onRejected


注意

:如果紧跟的

then

没有声明

onRejected

回调,则传给下一个

then

|

catch



onRejected

,还没有,接着传…如果走到头都没有,则报错Uncaught (in promise) Error:xxx


特殊的

:如果

resolve

的参数是Promise对象,且该Promise对象后面没有跟

then

,则该对象的

resolve

/

reject

会触发外层Promise对象后续的

then



onFulfilled/onRejected


五.基本语法

1.创建Promise对象

创建Promise的基本语法如下:

// 创建
var promise = new Promise(function(resolve, reject) {
	if (/*...*/) {
		resolve(data);
	}
	else {
		reject(new Error('error occurs'));
	}
});
// 使用
// then
promise.then(function(future) {
	// ...
}, function(error) {
	// ...
});
// catch
promise.catch(function(error) {
	// ...
});


注意



new Promise(func)

时,

func



立即执行

(不像generator只声明不执行),执行过程中遇到

resolve()

装没看见(P.S.简单理解为装没看见,解释见注释),遇到

reject()

立即抛出错误,对比例子如下:

new Promise(function(resolve, reject) {
	console.log('#1');
	resolve(1);
	console.log('#2');
});
// => #1 #2 不报错(遇到resolve装没看见)
// 其实内部属性[[PromiseStatus]]和[[PromiseValue]]都变了,但没有then提供的onFulfilled回调,看不到效果
new Promise(function(resolve, reject) {
	console.log('#1');
	reject(new Error('reject'));
	console.log('#2');
});
// => #1 #2 报错:Uncaught (in promise) Error: reject(…)
// 因为后面没有then/catch提供的onRejected回调,异常没有被消费掉

P.S.

reject

的参数可以是任意类型的,但一般都传入

Error

对象表示错误原因

2.Promise.prototype.then(onFulfilled, onRejected) 然后



promise

添加

onFulfilled/onRejected

回调handler,当

promise



resolve/reject

执行时触发对应handler


注意

:用

promise.then

添加回调函数时,如果

promise

已经处于

fulfilled



rejected

状态,那么相应的方法将会被

立即调用


返回一个Promise对象

(链式调用有戏),可以简单理解为:

1.如果触发了

onFulfilled

,则该对象的[[PromiseValue]]=onFulfilled的返回值,[[PromiseStatus]]=resolved

new Promise(function(resolve, reject) {
    resolve(2);
}).then(function(future) {
    return future * 2;
}, onRejected).then(onFulfilled, onRejected);
// onFulfilled拿到了4

2.如果触发了onRejected,则该对象的[[PromiseValue]]=onRejected的返回值,[[PromiseStatus]]=resolved


特别注意

:返回对象的状态是

resolved

,而

不是

rejected

new Promise(function(resolve, reject) {
    reject(2);
}).then(null, function(err) {
    return err * 2;
}).then(onFulfilled, onRejected);
// 还是onFulfilled拿到了4,而不是onRejected

P.S.实际上[[PromiseValue]]=undefined, [[PromiseStatus]]=pending,但仍将按照上述状态来执行

3.Promise.prototype.catch(onRejected) 捕获

等价于

then(null, onRejected)

,返回一个Promise对象,可以简单理解为:

1.如果触发了onReject,则返回对象的[[PromiseValue]]=onReject的返回值, [[PromiseStatus]]=resolved

2.如果onReject始终没有触发,则装作没看见catch,直接返回原Promise对象

var p = new Promise(function(resolve, reject) {
	resolve(2);
}).catch(function() {
	console.log('onRejected');
	return false;
});
p.then(onFulfilled, onRejected);
// onFulfilled拿到了2,catch没有任何影响

P.S.实际上[[PromiseValue]]=undefined, [[PromiseStatus]]=pending,但仍将按照上述状态来执行

4.Promise.all(iterable)

返回Promise对象,当

iterable

中所有

promise



resolve

后,触发

onFulfilled

,遇到第一个否定

promise

就立即退出,并触发

onRejected

//1.全肯定集合,触发onFulfilled,传入的参数是集合中所有promise的[[PromiseValue]]组成的数组    
Promise.all([getPromise(), getPromise()]).then(onFulfilled, onRejected);

//2.全否定集合,遇到第一个否定promise就退出,触发onRejected,传入的参数是该promise的[[PromiseValue]]
// Promise.all([getPromise(true), getPromise(true)]).then(onFulfilled, onRejected);

// 3.一般集合,同上
// Promise.all([getPromise(true), getPromise()]).then(onFulfilled, onRejected);

P.S.all,要么全都正常完成,要么因错误中断,全都停下来

5.Promise.race(iterable) 赛跑

返回Promise对象,当

iterable

中有任意一个

promise



resolve

后就立即退出,并触发

onFulfilled

,遇到否定

promise

就立即退出,并触发

onRejected

// 1.全肯定集合,遇到第一个肯定promise就退出,触发onFulfilled,传入的参数是该promise的[[PromiseValue]]
// Promise.race([getPromise(), getPromise()]).then(onFulfilled, onRejected);
// 2.全否定集合,遇到第一个否定promise就退出,触发onRejected,传入的参数是该promise的[[PromiseValue]]
// Promise.race([getPromise(true), getPromise(true)]).then(onFulfilled, onRejected);
// 3.一般集合,同上
// Promise.race([getPromise(true), getPromise()]).then(onFulfilled, onRejected);

P.S.“赛跑”,不论结果是肯定还是否定,只要最快的

6.Promise.resolve(value) 解决

1.如果

value



promise

,则把

promise



resolve/reject

的参数传递给对应的

onFulfilled/onRejected

Promise.resolve(getPromise()).then(onFulfilled, onRejected);
// onFulfilled拿到resolve的参数
Promise.resolve(getPromise(true)).then(onFulfilled, onRejected);
// onRejected拿到reject的参数

2.如果

value

是thenable对象(有

then

属性的对象),就会把

obj

包装成Promise对象,该对象的

then

就是

obj.then

Promise.resolve({
	then: function(onFulfilled, onRejected) {
		// onFulfilled(1);
		onRejected(new Error('obj.then err'));
		console.log('obj.then');
	}
}).then(onFulfilled, onRejected);

3.如果

value

是!thenable值,会把该值包装成Promise对象,该对象的[[PromiseValue]]=value, [[PromiseStatus]]=resolved,所以调用then方法时,onFulfilled将会接收到这个值

Promise.resolve(1).then(onFulfilled, onRejected);
// onFulfilled拿到1

7.Promise.reject(reason) 拒绝

会把

reason

包装成Promise对象,该对象的[[PromiseValue]]=reason, [[PromiseStatus]]=rejected,所以调用

then

方法时,

onRejected

将会接收到这个值


注意

:这里没有thenable/!thenable的区别,一视同仁:

// 1.!thenable onRejected将拿到Error对象
Promise.reject(new Error('static reject')).then(onFulfilled, onRejected);
// 2.promise onRejected将拿到被包起来的肯定Promise对象
// 该对象的[[PromiseValue]]=promise, [[PromiseStatus]]=rejected
Promise.reject(getPromise()).then(onFulfilled, onRejected);
// 3.thenable onRejected将拿到{then: xxx}
Promise.reject({
    then: function(onFulfilled, onRejected) {
        console.log('obj.then');
    }
}).then(onFulfilled, onRejected);

完整的测试DEMO:promise实例

六.高级用法

  • 配合生成器(

    generator

  • 配合

    async/await


  • 转载于http://www.tuicool.com/articles/uQ3uEzE,更多详情可以关注