- promise简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise是一个对象,从它可以获取异步操作的消息.
一.特点
- 1.对象的状态不受外界影响.Promise对象代表一个异步操作,有三种状态Pending(进行中),Resolved(已完成 又称Fulfiled)和Rejected(已失败).只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.
- 2.一旦状态改变就不会再变,任何时候都可以得到这个结果.Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected.只要这两种状态发生,状态就凝固了,不会再变了,会一直保持这个结果,如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果.这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的.
二.缺点
- 1.无法取消Promise,一旦新建它就会立即执行,无法中途取消
- 2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部.
- 3.当处于Pending状态时,无法得知目前进展到哪一阶段(刚刚开始还是即将完成)
三.基本用法
Promise对象是一个构造函数,用来生成Promise实例
let promise1 = new Promise((resolve, reject) => {
console.log('开始执行');
resolve('success');
reject('error');
});
promise1.then((value) => {
console.log(value)
}, (err) => {
console.log(err)
})
// 输出 开始执行 success
复制代码
function timeout(ms) {
return new Promise((resolve, reject) => {
console.log('开始执行')
setTimeout(resolve, ms, 'done');
});
}
timeout(1000).then((value) => {
console.log(value);
});
// 输出开始执行 1000毫秒后输出 done
复制代码
- 上面timeout方法返回一个promise,1000毫秒后执行resole方法
let p1 = new Promise((resolve, reject) => {
console.log('p1开始执行');
setTimeout(() => reject(new Error('fail')), 3000);
console.log('p1结束?');
})
let p2 = new Promise((resolve, reject) => {
console.log('p2开始执行');
setTimeout(() => resolve(p1), 1000)
})
p2.then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
// 输出 p1开始执行 p1结束? p2开始执行 3000毫秒后输出 fail
复制代码
- 上面方法中 p2的then方法的返回值为promise的实例p1,将先执行p1,在p1中3000毫秒后reject一个error,p2的catch方法输出这个error
四.’冒泡’
Promise对象的错误具有’冒泡’性质,会一直向后传递,直到被捕获为止,也就是说错误总会被下一个catch语句捕获
// bad
promise.then(data => {}, err => {});
// good
promise.then(data => {}).catch(error => {})
复制代码
- 面代码中,第二种写法要优于第一种写法,理由是第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch).因此建议使用catch方法,而不是使用then方法的第二个参数.
- 跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应 但是Chrome浏览器不遵守这条规定,它会抛出错误 “RfterenceError:”
五.几个小方法
1) Promise.all() 方法用于将多个Promise实例,包装成一个新的Promise实例
let pall1 = new Promise((resolve, reject) => {
resolve('resolve1');
reject('reject1');
})
let pall2 = new Promise((resolve, reject) => {
resolve('resolve2');
reject('reject2');
})
let pall3 = new Promise((resolve, reject) => {
resolve('resolve3');
reject('reject3');
})
let p1 = Promise.all([pall1, pall2, pall3]);
复制代码
- 上面代码中,Promise.all方法接收一个数组作为参数, pall1,pall2,pall3都是Promise对象的实例,如果不是,就会调用Promise.resolve方法,将参数转为Promise实例,再进一步处理.
p1的状态由p1,p2,p3决定分成两种情况
- 只有p1,p2,p3的状态都变成fulFiled, p1的状态才会变成fulFiled,此时p1,p2,p3的返回值组成一个数组,传递给怕的回调函数
- 只要p1,p2,p3之中的一个被rejected,p1的状态变成rejected,此时第一个被reject的实例的返回值,会传递给p1的回调函数
2)Promise.race() 方法将多个Promise实例,包装成一个新的Promise实例
let p = Promise.race([pall1, pall2, pall3]);
// 只要pall1, pall2, pall3之中的一个实例率先改变状态,p的状态就跟着改变,那个率先改变的Promise实例的返回值,就传递给p的实例,再进一步处理
复制代码
3)Promise.resolve() 将现有对象转为Promise对象
- 参数是一个Promise实例,那么Promise.resolve将不做任何修改,原封不动的返回这个实例
- 参数是一个thenable对象 thenable对象指的是具有then方法的对象
let thenable = {
then: (resolve, reject) => {
resolve(11);
}
}
// Promise.resolve方法会将这个对象转为Promise对象, 然后立即执行thenable对象的then方法
let pResoleve = Promise.resolve(thenable);
pResoleve.then(data => {
console.log(data)
})
复制代码
- 上面代码中,thenable对象的then方法执行后,对象pResolve的状态就变为resolved从而立即执行最后那个then方法指定的回调函数 输出11
- 参数不是具有then方法的对象,或根本就不是对象
let p4 = Promise.resolve('hello');
p4.then(data => {
console.log(data)
})
复制代码
- 如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved
- 上面代码生成一个新的Promise对象的实例p4,由于字符串不属于异步操作(判断方法是它不具有then方法的对象),返回promise状态从一生成就是Resolved,所以回调函数会立即执行,Promise.resolve方法的参数,会同时传给回调函数
- 不带任何参数
- Promise.resolve方法允许调用时不带参数,直接返回一个Resolved状态的Promise对象
4) Promise.reject()
- Promise.reject()方法也会返回一个新的Promise实例,该实例的状态为rejected
5) done()
- p1.then().done()
- Promise方法的回调链,不管是以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到,可以用done()方法,总是处于回调链的尾端,保证抛出任何可能出现的错误
6)finally()
- p2.then().done().finally()
- finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作,它与done方法最大的区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END