#nodejs的Promise
##参考
##说明
- 笔者环境为Ubuntu16.04、node6.×.×,使用语言版本为ES6
##Promise介绍
-
Promise是nodejs异步编程的一种方式,ES6把Promise写入了语言标准,原生支持了Promise语法
-
Promise包括的类方法有:Promise.resolve()、Promise.reject()、Promise.all()、Promise.race()
-
Promise包括的原型方法有:Promise.prototype.then()、Promise.prototype.catch()
-
prototype代表Promise的原型,nodejs的对象方法、类方法和原型方法的知识点自行查阅资料
-
Promise对象有三种状态,pending、resolved、rejected,其中resolved和rejected都为结束状态,rejected代表抛出异常的状态,会调用then方法中的第二个回调函数,或者被catch方法处理,具体见下文
-
resolve(<参数>)和reject(<参数>)可以改变Promise对象的状态,一旦Promise对象成为其中一种结束状态,Promise的状态便不可被改变了,但是在改变状态之后的代码还是会执行的(这是不应该的,所以建议不要在resolve(<参数>)或reject(<参数>)之后还有操作,最好直接return resolve(<参数>)或return reject(<参数>))
new Promise((resolve,reject)=>{ resolve('resolve'); reject("reject"); console.log("aaaaaaaaa"); }).then((a)=>{ console.log(a); }).catch((err)=>{ console.log(err); }); 结果: aaaaaaaaa resolve
-
Promise的异常如果不捕获,是不会中断程序的,会被nodejs的unhandledRejection事件监听到并在控制台报出unhandledRejection异常,也就是说如果上层没有异常,而Promise内发生异常,程序依然正常执行并退出,退出码为0
new Promise((resolve,reject)=>{ reject("reject"); }).then((a)=>{ console.log(a); }); 结果: UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): reject exited with status 0
-
Promise的Promise.resolve()、Promise.reject()和new Promise()的方式并不能实现异步,then和catch的回调函数才是异步的内容
-
另外,Promise.resolve()、Promise.reject()以及new Promise()返回的Promise对象直接就是对应的状态;而then、catch由于异步,会先返回一个pending状态的对象,直到异步完成改变它的状态;all、race会在把所有数组元素转为Promise后返回一个pending状态的Promise,然后根据数组中的Promise的最终状态确定它的状态
##Promise.resolve
- 这个方法有一个参数,返回一个resolved状态的Promise对象
- 相当于new Promise((resolve, reject) => resolve(<参数>))
- 如果传入的是一个Promise对象,那么什么都不做直接返回该对象
- 如果传入的是一个thenable对象(一个具有then方法的对象),那么会先执行then方法然后返回执行then后的Promise对象
- 如果不是Promise或者thenable对象(比如字符串),会将参数直接作为后续方法(比如then)的参数
- 可以不带参数,这时直接返回一个Promise对象
##Promise.reject
- 这个方法有一个参数,返回一个rejected状态的Promise对象,但是有一点特别的是,它的参数不管是什么,都会原封不动的作为后续方法(比如then)的参数
- 相当于new Promise((resolve, reject) => reject(<参数>))
- 可以不带参数,这时直接返回一个Promise对象
##Promise.all
-
这个方法的参数是一个数组,如果数组成员不是Promise对象,就会先调用上面的Promise.resolve方法变成一个Promise再进一步处理
-
方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise对象
-
返回一个Promise,当数组的所有Promise状态为resolved时,返回的Promise对象状态才是resolved,所有的Promise对象的返回值成为一个数组作为返回的Promise的返回值
var a = new Promise((resolve,reject)=>{ resolve("resolve1"); }); var b = new Promise((resolve,reject)=>{ resolve("resolve2"); }); var c = new Promise((resolve,reject)=>{ resolve("resolve3"); }); Promise.all([a,b,c,'22']).then((t)=>{ console.log(t[0]); console.log(t[1]); console.log(t[2]); console.log(t[3]); }); 结果: resolve1 resolve2 resolve3 22
-
如果数组中有一个Promise对象的状态变为rejected,那么返回的Promise状态为rejected,此时第一个被reject的Promise的返回值会成为返回的Promise对象的返回值
var a = new Promise((resolve,reject)=>{ resolve("resolve1"); }); var b = new Promise((resolve,reject)=>{ reject("reject2"); }); var c = new Promise((resolve,reject)=>{ reject("reject3"); }); Promise.all([a,b,c,'22']).then((t)=>{ console.log(t[0]); console.log(t[1]); console.log(t[2]); console.log(t[3]); },(t)=>{ console.log(t); }); 结果: reject2
##Promise.race
-
这个方法的参数是一个数组,如果数组成员不是Promise对象,就会先调用上面的Promise.resolve方法变成一个Promise再进一步处理
-
方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise对象
-
返回一个Promise,当数组中有Promise对象改变状态时,返回的Promise对象就会确定了一样的状态,此时的Promise的返回值会成为返回的Promise对象的返回值
var a = new Promise((resolve,reject)=>{ setTimeout(()=>reject('reject'), 1000); }); var b = new Promise((resolve,reject)=>{ console.log('111'); setTimeout(()=>console.log('222'), 1100); setTimeout(()=>resolve("resolve"), 2000); }); Promise.race([a,b]).then((t)=>{ console.log(t); },(t)=>{ console.log(t); }); 结果: 111 reject 222
##Promise.prototype.then
-
由两个回调函数作为参数,第一个是Promise的resolved状态的回调,第二个是Promise的rejected状态的回调
-
返回的依然还是一个新的Promise对象,未执行回调函数时状态是pending,而执行后,不管是第一个还是第二个回调函数,默认返回的Promise最后是resolved状态,如果要使then方法返回的Promise最后是rejected状态,需要在回调函数里面使用return返回一个最后是rejected状态的Promise对象
-
可以采用链式的写法,在then后面再接着then,如果前一个then第一个回调为空,Promise的resolved状态的返回值,会被传递到下一个then;如果前一个then第二个回调为空,Promise的rejected状态的返回值,会被传递到下一个then或者catch;注意,即使回调的参数列表为空那也是有这个回调,返回值就会被处理掉
Promise.resolve('resolve').then((result)=>{ console.log(result); return Promise.reject('reject'); },(result)=>{ console.log(result); }).then(()=>{}).then((result)=>{ console.log(result); },(result)=>{ console.log(result); }); 结果: resolve reject
##Promise.prototype.catch
- 其实就是.then(null, rejection)的别名,用于捕获rejected状态
- 建议使用这个方法,取代then的第二个回调函数,提高代码可读性
##自己给Promise添加原型方法
Promise.prototype.funcName = function(onResolve, onReject) {
......
}
onResolve和onReject是和then一样的回调参数,可以有也可以没有,至于函数内容自己定义,只要符合nodejs的语法就可以了,用this表示Promise的原型对象