语法
new Promise( function(resolve, reject) {...} /* executor */ );
复制代码
executor
是带有 resolve
和 reject
两个参数的函数 。Promise构造函数执行时立即调用executor
函数, resolve
和 reject
两个函数作为参数传递给executor
(executor 函数在Promise构造函数返回新建对象前被调用)。resolve
和 reject
函数被调用时,分别将promise的状态改为_fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成_fulfilled,或者在发生错误时将它的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。
一个 Promise
有以下几种状态:
-
pending: 初始状态,既不是成功,也不是失败状态。
-
fulfilled: 意味着操作成功完成。
-
rejected: 意味着操作失败。
使用promise
let status = 1;
// 判断status是否为1,是1的时候执行成功
let p1 = new Promise(function(resolve,reject){
if(status==1){
resolve({msg:"执行成功",status:"200"}); // 这里传递给resolve的数据就是之后then中接受到的res
}else{
reject({msg:"执行失败",status:"404"}); // 对应catch中的err
}
});
p1.then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
复制代码
Promise的一些注意点
Promise的理解
promise可以看成是去肯德基买汉堡,先预定一个汉堡,然后收营员会给你一小票并向你承诺之后会给你一个汉堡(也可能汉堡买完了没有汉堡)。从下单到获得汉堡的这个过程可以看成是异步的操作,期间你可以刷一会儿手机,同时后厨在准备汉堡。有了汉堡之后吃汉堡(处理resolve),或者没有汉堡了发生退款(处理reject)。
你在等待这个承诺的到来,一旦到来你就可以开始吃汉堡或者没有汉堡遗憾的退款。
- new 出来的Promise对象就是收银员的承诺
- then 中的第一个回调就是收到汉堡最后吃汉堡的操作
- then中的第二个回调就是没有汉堡了退款的操作
- Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的
对于then的理解
then
并不是处理promise
实例返回的resolve
状态值,resolve
和reject
状态的值都能够处理,第一个回调函数处理成功,第二个回调函数处理失败,如果缺省第二个处理失败的回调,则状态为reject
的promise
传递到下一个链式调用。
Promise实例状态的变化
只有两种变化过程,而且变化之后之后不会发生变化,会保持状态的一致
只能从 _pending -> fulfilled 或者 从 pending -> rejected _一旦状态发生变化就不会再发生改变,保持一致性。(你去买汉堡只可能有两种状态,买到汉堡和没有买到,而且不可能在两者之间变化)
- promise对此调用的结果保持一致,不会发生改变
- 在Promise的构造调用的时候只能发生一次状态转变,一旦转变之后不会发生变化
var promise = new Promise((resolve, reject) => {
// 只能改变一次状态
resolve('1') // 改变状态
resolve('2') // 不生效
resolve('3') // 不生效
console.log('4') //同步执行
})
// 多次调用promise中的值不会发生变化
promise.then((data) => {
console.log('第一个then', data)
})
promise.then((data) => {
console.log('第二个then', data)
})
// 4
// 第一个then 1
// 第二个then 1
复制代码
then,catch执行之后会返回一个新的promise
promise
可以链式调用不是因为使用return this
, 而是在then
和catch
之后返回了一个promise
then
或者catch
返回立即值,则返回的promise
是resolved
状态,相当于Promise.resolve(..)
- 抛出现异常或者返回
Promise.reject(..)
,则返回的promise
是rejected
状态
var promise = new Promise((resolve, reject) => {
resolve('1')
})
promise.then((data) => {
console.log(data) // 1
return 2 // 作为新的promise的resolve值返回
}).then((data) => {
// 这里接收的是上一个then返回的新的promise的resolve状态
console.log(data) // 2
})
promise.then((data) => {
// 可以返回一个promise
return Promise.reject('错误')
}).catch((data) => {
// catch接收上一个then返回的promise
console.log(data) // 错误, 接收上一个链上的promise的resolve返回
}).then((data) => {
console.log(data) // undefined 前一个链上的promise没有返回值
})
promise.then((data)=>{
// 抛出错误
throw new Error('出错')
}).catch((err) => {
// 上一个promise返回的是reject, 内容是 抛出的error
console.log(err)
})
// 1
// 2
// Error: 出错
// at promise.then (3.html:32)
// 错误
// undefined
复制代码
异常处理的一些问题
- 直接通过
return new Error('错误')
的方式返回异常不能被下一个catch
捕获到,这里返回的promise
是resolve
状态,会被传递下去被then
捕获,只有throw new Error()
才能被下一个catch
捕获
var promise = new Promise((resolve, reject) => {
resolve('1')
})
promise.then((data) => {
return new Error('错误')
}).catch((err) => {
console.log('不会执行')
}).then((data) => {
console.log('打印之前返回的错误', data)
})
// 打印之前返回的错误 Error: 错误
// at promise.then (4.html:16)
复制代码
then(success, error)
then
可以由两个处理函数,第一个用来处理resolved
状态的promise
返回值,第二个用来处理rejected
状态的promise
返回值,这里处理的是链式调用的返回的前一个promise
var promise = new Promise((resolve, reject) => {
reject('错误')
})
promise.then((data)=>{
console.log('不会执行,promise状态是rejected')
}, (err)=>{
// 捕获到错误
console.log(err) // 错误
}).catch((err) => {
// 链式调用的前一个promise返回是一个resolve状态
console.log('不能捕获到错误')
})
复制代码
then
中没有指定处理rejected
状态的函数时,错误状态会一直传递下去直到被处理,要是没有处理不会被window
捕获,直接控制台报错...
window.addEventListener('error', (e) => {
console.log(e)
})
var promise = new Promise((resolve, reject) => {
reject('错误')
})
promise.then((data)=>{
console.log('未对错误处理')
}).catch((err) => {
// 执行
console.log('上一个then中缺省处理错误的函数,错误会被封装成新的promise向下传递', err)
})
promise.then((data)=>{
console.log('不处理,也没有后续,错误会被window捕捉到')
})
复制代码
.then
的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的.catch
可以捕获之前的错误
var promise = new Promise((resolve, rejected) => {
resolve(1)
})
promise.then((data)=>{
throw new Error('2')
}, (err) => {
console.log('不能捕获,then中第一个成功回调返回的错误')
}).catch((err)=>{
console.log('可以捕获上一个then中成功或者错误处理函数中抛出的错误')
})
复制代码
Promise.resolve() 对于传入值的处理
- 传入一个立即数 如 数字,字符串,则包装成一个新的promise返回
- 传入的是一个真正的promise,则返回这个promise
- 传入的是一个thenable的值,则会解封到不是thenable为止
// 传入立即数
Promise.resolve(1).then((data)=>{console.log(data)}) // 1
// 传入promise对象
var p1 = new Promise((resolve,reject) => {
resolve(2)
})
var p2 = Promise.resolve(p1)
console.log(p1 === p2) // true 返回同一个
// thenable
var o = {
then:function(cb,err){
console.log('then函数')
cb(3)
}
}
Promise.resolve(o).then((data)=>{console.log(data)}) // then函数 3
复制代码
判断一个函数是不是thenable
if(!!p
&&
(typeof p === 'object' || typeof p === 'function')
&&
(p.then && typeof p.then === 'function')
) { console.log(true)} else {
console.log('false)
}
复制代码
用来控制请求的执行顺序
Promise.all
方法常被用于处理多个promise
对象的状态集合。输入是一个由promise
对象组成的数组,所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable
里面的promise
对象失败则立即触发该promise
对象的失败。这个新的promise
对象在触发成功状态以后,会把一个包含iterable
里所有promise
返回值的数组作为成功回调的返回值,顺序跟iterable
的顺序保持一致;如果这个新的promise
对象触发了失败状态,它会把iterable
里第一个触发失败的promise
对象的错误信息作为它的失败错误信息。
这时候可以这样,将一组ajax请求封装成一组promise
对象传入Promise.all
,返回结果也是有序的,再对这个有序的promise
对象进行处理
用来控制请求超时
Promise.race
当iterable
参数里的任意一个子promise
被成功或失败后,父promise
马上也会用子promise
的成功返回值或失败详情作为参数调用父promise
绑定的相应句柄,并返回该promise
对象。(任意一个成功或者失败就触发)
此时可以构造一个 定时器任务和一个ajax
请求,封装成promise
对象传入Promise.race
,如果定时器的结果先返回,则请求超时