在JavaScript中代码都是单线程执行的,因此JavaScript中所有的网络操作、浏览器事件都必须异步执行。在Promise
之前JavaScript处理异步的方式都是回调函数。可以说callback
的方式已是深入人心,那Promise
又是解决什么问题的呢?看下面一段代码:
$.get('/getList',function(){
$.get('/getCount',function(){
$.get('/getDetail',function(){
//....
})
})
})
这段代码就是传统的callback
方式处理异步,可以看到刚刚3级嵌套代码层级就已经比较乱了,如果再加上一些逻辑代码那简直是无法直视。这就是我们常说的回调地狱问题。代码可读性低,难以复用。
Promise解决回调地狱
Promise
的基本用法
var promise = new Promise((resolve,reject)=>{
setTimeout(function(){
//这里异步操作已经执行完了,就可以通过resolve告诉外界可以进行其他操作了
resolve('ok');
//reject('no');
},2000);
})
promise.then(res=>{
console.log(res); // ok
},err=>{
console.log(err); // no
})
通过Promise
处理异步,先执行异步操作,不关心如何处理结果,通过Promise
对象的返回成功还是失败,在将来的某个时刻执行结果处理函数。
resolve && reject
上面代码我们通过 resolve 方法把 Promise 的状态置为完成态(Resolved),这时 then 方法就能捕捉到变化,并执行“成功”情况的回调。
而 reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”情况的回调(then 方法的第二参数)。
Promise实现多层回调
同样三级回调的代码我们再使用Promise
重构一遍
new Promise((resolve,reject)=>{
$.get('/getList',res=>{
resolve(res);
});
}).then(res=>{
return new Promise((resolve,reject)=>{
$.get('/getCount',res=>{
resolve(res);
});
});
}).then(res=>{
return new Promise((resolve,reject)=>{
$.get('/getDetail',res=>{
resolve(res);
})
});
}).then(res=>{
//...
});
可以看到无论有多少层回调,都不用互相嵌套,只需要等待Promise
对象“通知“执行即可。
Promise.all
当需要进行多步没有关联逻辑的异步操作时,可以使用Promise.all
Promise.all([
$.get('/getList'),
$.get('/getCount'),
$.get('/getDetail')
]).then(([data1,data2,data3])=>{
//then回调的参数是一个数组,顺组数序就是异步操作书写顺序
console.log(data1,data2,data3);
},err=>{
console.log(err);
});
all
方法中的参数应该是Promise
对象,因为ajax
函数返回的对象就是promise对象所以这里是可以执行的;- 此种方式只适用于异步操作之间无逻辑关联;
- 不论异步操作执行顺序如何,最后都会按照书写顺序返回(
data1,data2,data3
是按照异步操作书写顺序返回); - 如果如其中一个出错就会执行错误回调;
Promise.race
race
的用法与all
相似,不同点就是all
会等所有异步操作全部执行完后再执行then回调,而race
中只要有一个异步操作执行完成就立刻执行then回调。
Promise.race([
new Promise(function(resolve, reject){
setTimeout(function(){
console.log('函数一执行!');
resolve('11');
}, 1000);
}),
new Promise(function(resolve, reject){
setTimeout(function(){
console.log('函数二执行!');
resolve('22');
}, 1200);
})
]).then(result=>{
console.log('then执行');
console.log(result);
},err=>{
console.log(err);
});
//执行结果为:
//函数一执行!
//then执行
//11
//函数二执行!
可以看到函数一执行明显要比函数二快,所以执行了函数一后立即执行了then回调,注意这时函数二依然会执行,但是执行后不会再触发then回调的执行。
Promise错误处理
- 第一种方式,通过
then
。
new Promise((resolve,reject)=>{
//...
}).then(resSuccess=>{
//成功
},resError=>{
//失败
});
- 第二种方式,
catch
捕获
new Promise((resolve,reject)=>{
//...
}).then(resSuccess=>{
//成功
}).catch(resError=>{
//失败
});
注:catch
方式更常用,因为不仅仅能捕获到reject传递的参数,还可以捕获到成功的回调中发生的错误。
未完。。。