Promise对象:
- 一个保存异步操作事件的对象
- 三种状态,Pending、Fulfilled、Rejected。状态只会由“Pending→Fulfilled”或者“Pending→Rejected”,且状态改变就不会再变
/*Promise对象是由一个构造函数生成实例,接受函数为参数 函数的参数为resolve和reject。这两者,也是函数*/ var promise = new Promise ( function(resolve , reject){ /*一些异步操作*/ if(/*异步操作成功*/){ //当调用resolve函数的时候,Promise对象状态由,Pending → Fulfilled //将value值进行传递(一般是异步操作成功后的结果) resolve(value) } else { //当调用reject函数的时候,Promise对象状态由,Pending → Rejected //将error值进行传递 reject(error) } })
总体上来说,Promise对象,更像是一个事件的容器,但Promise对象状态的改变并不受事件的完成而完成,而是由参数函数中的 resolve 和 reject 函数来指定它什么时候改变状态。
比如下面代码:
var promise = new Promise ( function(resolve , reject){ let i = 0//标记事件已完成,传字符串resolved值给.then()处理 resolve(i)
i += 1 }) .then( //then方法是指,当Promise状态由Pending改变为Resolved时,立即调用 (value) = > { console.log(value) } )
---------------------------------------------------------------
最后输出:
0
then()方法下面会继续讲,问题来了,上面代码“ i += 1”是否会运行呢?再看
var promise = new Promise ( function(resolve , reject){ resolve() console.log('A') setTimeout(() => { console.log('B') }, 3000) }) .then(() = > { console.log('Resolved') }) --------------------------------------------------------------- 先后输出: A Resolved B //3000ms后输出B
Promise对象在状态改变后,内部的代码还是会运行。当内部同步任务全部执行完成后,再调用then()方法。因此前两行最先输出的是‘A’和‘Resolved’,由于B是一个异步事件,所以在3000ms后被调用输出。
如果想在状态改变后直接结束,不执行之后的语句,最好不要将异步操作放在状态改变语句之后!当然也可以这样:
var promise = new Promise ( function(resolve , reject){ //在前面加上return return resolve() console.log('A') setTimeout(() => { console.log('B') }, 3000) }) .then(() = > { console.log('Resolved') }) --------------------------------------------------------------- 最后只输出: Resolved
原型方法 —— then()
- 该方法是定义在Promise对象原型上的方法,即Promise.prototype.then()
- 且then()方法返回一个新Promise实例
顾名思义,Promise实例状态改变后,要做什么。该方法为其添加了回调函数。Promise实例有两种状态,自然也提供了两种回调(Resolved 和 Rejected)
上面已经简单涉及了该方法,这里整理一下:
var promise = new Promise ( function(resolve , reject){ //做些什么... if(/*异步操作成功*/){ resolve(value) } else { reject(error) } }) .then( //then方法接受两个回调函数为参数,以下 //第一个Promise实例变为Resolved状态调用 //函数中的参数value,接受Promise实例中resolve(value)传递的value值 (value) => { /*success*/ }, //(可选)第二个Promise实例变为Rejected状态调用 ////函数中的参数error,接受Promise实例中reject(error)传递的error值 (error) = > { /*failure*/ } )
-
then()的链式调用
上面说了then方法返回一个新的Promise实例,那么就可以promise.then().then().then().then().then().....这样的链式调用了。
var promise = new Promise ( function(resolve , reject){ resolve(A) }) .then( (value) => { //此处参数 value 接受 resolve(A) 中的传递值 A //输出A console.log(value) return B }).then( (value) => { //此处参数 value 接受上一级then()方法中return的值 //输出B console.log(value) }).then( (value) => { //上一个then方法无return时 //输出undefined console.log(value) }) ----------------------------------------------------------------- 先后在控制台上输出: A B undefined
若then()方法中传入的不是函数,则在链式调用中,此then()方法会被忽略,值会传入下一个then方法中
var promise = new Promise ( function(resolve , reject){ resolve(A) }) .then(1) //这个then方法被忽略 .then( (value) => {console.log(value)} ) ----------------------------------------------------------------- 控制台上输出: A
原型方法 —— catch()
- Promise对象原型方法,Promise.prototype.catch()
- 等同于.then( null , reject(error) )
- catch()方法返回一个Promise对象
一般应用如下
var promise = new Promise ( function(resolve , reject){ if(/*异步操作成功*/){ resolve(value)} else { reject(new Error ('promise'))} }) .then( (value)=>{ if(/*异步操作成功*/){ return A } else { throw new Error('error_A') } }).then( (value)=>{ if(/*异步操作成功*/){ return B } else { throw new Error('error_B') } }).then( (value)=>{ if(/*异步操作成功*/){return C } else { throw new Error('error_C') } }).catch( (error)=>{ /*此处catch捕获以上从Promise对象到任意then方法所抛出的错误*/ console.log(error) //catch只能捕获被调用之前抛出的错误,之后的错误如'error_D'就无法捕获 }).then( (value)=>{ //上面的catch返回一个Promise对象因此可以继续调用then方法 if(/*异步操作成功*/){return D } else { throw new Error('error_D') } })
静态方法
- Promise.all()
- Promise.race()
- Promise.resolve()
- Promise.reject()
Promise.all()
将多个Promise实例包装,并且返回一个新的Promise实例
当包装中所有的Promise状态都变为Resolved时,返回结果数组,数组中返回值的顺序安装包装的数据排列
Promise.all([ promise_A, promise_B, promise_C ]).then(result=>{ console.log(result) }) --------------------------- //当promise_A,promise_B,promise_C状态都为Resolved时,result输出一个结果数组: [result_A,result_B,resultC]
当Promise集合中有一个Promise最终状态为Rejected,就会被Promise.all()的catch方法进行捕获
Promise.all([ new Promise((resolve, reject) => { setTimeout(() => { console.log('A') reject(new Error('AAAAAAAAAAA')) }, 5000) }), new Promise((resolve, reject) => { setTimeout(() => { console.log('B') reject(new Error('BBBBBBBBBBB')) }, 2000) }).catch(e => { return e }) ]).then(result => { console.log(result) }).catch(e => { console.log(e) }) } ---------------------------------------------- 控制台先后输出: B //2s后输出B A //5s后输出A AAAAAAAAAAA //A输出后立即输出错误'AAAAAAAAAAA'
上面代码中为什么Promise. all最后捕获的是错误'AAAAAAAAAAA'而不是‘BBBBBBBBBBB’。因为在第二个Promise实例中,2秒后虽然状态变为Rejected并且抛出了Error,但是被自身之后的catch方法捕获了该错误且return。之前已经知道,Promise之后的then和catch方法其实返回的是一个新的Promise实例,若方法中没有抛出新的错误,其后续的状态就会变为Resolved。而第一个实例抛出错误后,并未被后续方法捕获,最后状态为Rejected,错误最终被外层Promise. all方法的后续catch所捕获,最后输出'AAAAAAAAAAA'。
Promis.race()
与上面方法一样,同样将多个Promise实例包装成一个新的Promise实例。
Promise.race([P1,P2,P3]) .then( value => { /*do something*/ } ) .catch(e => { /*do something*/ })
Promise实例组中,P1、P2、P3谁的状态先发生变化(Resolved 或 Rejected),Promise.race()状态也发生改变,P1(or P2 or P3)的返回值传递给Promise.race()回调函数。
Promise.resolve()
将一个对象转为一个Promise对象,以下几种情况
①
let p = new Promise( (resolve,reject) => { resolve(1)} ) //传入Promise对象p,返回还是p Promise.resolve(p)
②
//传入一个非thenable对象(thenable对象,就是一个对象具有then方法,下面会说明),或者非对象 Promise.resolve('_JayKoo') -------------------------------------- //上面代码等同于 new Promise( (resolve,reject) =>{ resolve('_JayKoo'); })
③
//thenable对象,具有then方法的对象 //then方法满足以下格式 let obj = { then(res , rej){ //then函数,参数满足Promise回调函数中的参数格式。then函数,相当于,Promise构造函数中的回调函数格式。 if(/*Resolved*/){ res(value) } else { rej(error) } } } //将obj转为Promise对象,且立即调用then方法 Promise.resolve( obj ) --------------------------------------------------------------------------- //以上代码的效果等同于立即执行了 new Promise( (res, rej) => { /*obj对象中的操作*/ if(/*Resolved*/){ res(value) } else { rej(error) } })
④
//不带参数,立即生成一个Promise对象 //Promise.resolve()方法的执行,是在本轮注册的所有同步脚本事件的结束时(非异步) let p = Promise.resolve()
Promise.reject()
Promise.reject()同样返回Promise对象.。
在Promise.resolve()中,传入的参数由thenable对象和非thenable对象两种情况,且之后的参数调用情况也不同。
但在Promise.reject()中,所有传参都会被当做Error抛出。
let p = Promise.reject(thenable) -------------------------------------- //等同于 let p = new Promise( (resolve,reject) => { //即使是个thenable对象,也会原封不动地将这个对象当做错误信息抛出 reject(thenable) }) -------------------------------------- p.catch( e => { console.log( e === thenable) }) //true