一、为什么会出现promise?
在实际开发过程中,经常会遇到某些耗时的js操作。其中,包含异步操作也包含同步操作,但是他们都不是立马可以得到结果的。此时,一般会为其指定一个回调函数,即事先规定,一旦他们运行结束,应该会调用那些函数。
JS采用回调来处理异步编程,但是如果出现多层嵌套,也就是常说的"回调地狱"。"回调地狱"不但维护困难,也更容易滋生bug。因此promise出现。
Promise将原来回调地狱中的的回调函数,从横向变为纵向。
//回调地狱
asyncOperation(function (data) {
// 处理data
anotherAsync(function (data2) {
// 处理data2
yetAnotherAsync(function () {
//完成
});
});
});
//Promise
PromiseSomething()
.then(function (data) {
// 处理data
return anotherAsync();
})
.then(function (data2) {
// 处理data2
return yetAnotherAsync();
})
.then(function () {
//完成
})
二、Promise规范
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)。
- 一个promise状态只可能从"等待"转到"完成"态或者"拒绝"态,不能逆向转换,同时"完成"和"拒绝"状态不能相互转换。
- promise必须实现then方法(可以说,then是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟他们被定义时的顺序一致。
- then方法接收两个参数,成功回调,失败回调。
三、Promise优缺点
优点
- 有了Promise对象避免了回调地狱
- Promise对象提供统一的接口
缺点
- 无法取消promise,一旦建立立即执行。
- 如果不设置回调函数,Promise内部抛出的错误,不会反映到外部。
- 当出于pending状态时,无法得知目前在哪一个阶段。
四、Promise 基本API
- Promise.resolve() :生成一个成功的promise对象
- Promise.reject():生成一个错误的promise对象
- Promise.prototype.then():核心部分(返回一个新的promise)
- Promise.prototype.catch():异常捕获
- Promise.all()
- Promise.race()
Promise.all()
- 接收promise对象组成的数组作为参数
- 当这个数组里所有的promise对象全部变成resolve或遇到第一个reject状态的时候,才会去调用.then方法。
- 传递给Promise.all的promise并不是一个个顺序执行的,而是同时开始,并行执行的。
Promise.race()(最先执行的promise结果)
- 只要有一个promise对象进入resolve或者reject状态的话,就会调用后面的.then方法
- 如果一个promise对象执行完了,还会继续执行后面的对象,因为promise无法中断
五、Promise基本用法
1、创建promise对象
- new Promise(fn)返回一个promise对象
- 在fn中指定异步等处理
- 在处理结果正常时,调用resolve
- 处理结果异常,调用reject
function createPromise(URL) { return new Promise(function (resolve,reject) { var req = new XMLHttpRequest(); req.open('GET',URL,true); req.onload = function () { if(req.status === 200){ if(req.readyState ===4){ resolve(req.responseText); } }else { reject(new Error(req.responseText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }) } // 示例 var URL = "http://www.baidu.com"; createPromise(URL) .then(function onFuilled(value) { console.log(value); }) .catch(function onRejected(error) { console.log(error); }) //.catch只是promise.then(undefined,onRejected)的别名
2、promise.prototype.then()
-
它的作用是为Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。
-
then方法返回的是一个新的Promise实例。因此可以采用链式写法,即then方法后面再调用另一个then方法。
3、Promise.prototype.catch()
Promise.prototype.catch方法是.then(null,rejection)的别名,用于指定发生错误时的回调函数。
createPromise(URL).then(function (value) { }).catch(function (error) {
console.log(error);
});
4、Promise.resolve()
有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用。
该函数的参数四种情况:
(1)参数是一个Promise实例,那么Promise.resolve将不做任何操作,原封不动的将实例返回。
(2)参数是一个thenable对象,会将其转为Promise对象,然后立即执行该对象的then方法。
(3)参数不是具有then方法的对象,或根本就不是对象。比如说字符之类,则Promise.resolve方法返回一个新的Promise对象,并且状态Resolved。
(4)不带有任何参数,直接返回一个状态为Resolved的Promise对象。
- 使用Promise.resolve()创建Promise对象
/*静态方法 Promise.resolve(value) 可以认为是 new Promise() 方法的快捷方式。*/
//比如
Promise.resolve(1)
.then(function(value){
console.log(value);
});
//可以认为是以下代码的语法糖。
new Promise(function(resolve){
resolve(1);
})
.then(function(value){
console.log(value);
});
// 控制台输出1
注意: 无论Promise.resolve的参数是什么,只要变成了rejected,或者resolved。都会执行then里面的resolve函数
5、Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
Promise.reject('这是错误的信息').then(function(){
},function(res){
console.log(res); //这里是错误信息
});
注意: 无论Promise.reject的参数是什么,只要变成了rejected,或者resolved。都会执行then里面的reject函数。
6、Promise.all()
7、Promise.race()
六、将定时器setTimeout Promise化
function timer(fn,time) {
return function () {
return new Promise((resolve,reject)=>{
setTimeout(function(){
fn();
resolve();
},time);
});
}
}
Promise.resolve()
.then(
timer(function () {
console.log('1')
},1000)
)
.then(()=>{
console.log('2');
});