ES6 Promise 用法讲解
- Promise是异步编程的一种解决方案,用于一个异步操作的最终完成(或失败)及其结果值的表示,比传统的回调函数方案更加合理。
- Promise是一个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。
var p = new Promise((resolve, reject)=>{
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数
用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数.
function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
return p; //在我们包装好的函数最后,会return出Promise对象,Promise对象上有then、catch方法
}
runAsync() //包在一个函数里,需要的时候去调用它
- reject的用法:reject的作用就是把Promise的状态置为rejected,在then中就能捕捉到,然后执行“失败”情况的回调
function getNumber(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的随机数
if(num<=5){
resolve(num);
}
else{
reject('数字太大了');
}
}, 2000);
});
return p;
}
getNumber()
.then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason, data){
console.log('rejected');
console.log(reason);
}
);
getNumber函数用来异步获取一个数字,2秒后执行完成,如果数字小于等于5,我们认为是“成功”了,调用resolve修改Promise的状态。否则我们认为是“失败”了,调用reject并传递一个参数,作为失败的原因
运行getNumber并且在then中传了两个参数,then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调。所以我们能够分别拿到他们传过来的数据
- catch的用法:Promise对象除了then方法,还有一个catch方法,它和then的第二个参数一样,用来指定reject的回调。如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
在项目中用到:
save_del() {
return new Promise((resolve, reject) => {
//删除
if (this.del_stem_arr.length > 0 || this.del_answer_arr.length > 0) {
checkstemdelete
.post(
{
checkStem: this.del_stem_arr,
checkStemInfo: this.del_answer_arr
},
this
)
.then(res => {
console.log(res)
if (res) {
resolve('删除题目成功')
this.del_stem_arr = []
this.del_answer_arr = []
} else {
reject('删除题目失败')
}
})
.catch(() => {
reject('删除题目失败')
})
} else {
resolve('无删除题目')
}
})
},
- all的用法:Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调
例如一个方法需要调多个接口时,用promise.all更合适
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
}); // 有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据
两个个异步操作是并行执行的,等到它们都执行完后才会进到 then 里面。同时 all 会把所有异步操作的结果放进一个数组中传给 then
//切菜
function cutUp(){
console.log('开始切菜。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('切菜完毕!');
resolve('切好的菜');
}, 1000);
});
return p;
}
//烧水
function boil(){
console.log('开始烧水。');
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log('烧水完毕!');
resolve('烧好的水');
}, 1000);
});
return p;
}
Promise
.all([cutUp(), boil()])
.then(function(results){
console.log("准备工作完毕:");
console.log(results);
});
项目中:
//保存
save() {
return new Promise((resolve, reject) => {
let arr = []
this.$refs.checkItem.map(object => {
arr.push(object.validate())
})
Promise.all(arr).then(
async () => {
try {
await this.save_del()
await this.save_updateAddAdd()
resolve('保存成功')
} catch (error) {
reject(error)
}
},
() => {
reject('请填写所有的必填项')
}
)
})
},
- race的用法: all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,这个词本来就是赛跑的意思。race的用法与all一样
只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。
注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作
//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
requestImg函数会异步请求一张图片,我把地址写为"xxxxxx",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息