Promise是一个构造函数,它接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。不过按照标准来讲,resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。它本身有all、reject、resolve这几个的方法,原型上有then、catch、race等的方法,下面为大家详细介绍其用法。
```
var p = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 1000);
});
```
在上面的代码中,执行了一个异步操作,1秒之后,输出“执行完成”,并且调用resolve方法。看到这里,你可能会注意到,我们并没有调用函数,Promise自动进行了执行,所以我们一般把Promise放到函数里面,示例如下:
```
function run(){
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log("执行完成");
resolve("随便什么数据");
},1000);
});
return p;
}
```
then方法
在函数最后,会return出Promise对象,然后我们就可以调用它的then方法:
```
run().then(function(data){
console.log(data);
});
```
在run()的返回上直接调用then方法,then接收一个参数,是函数,并且会拿到我们在runAsync中调用resolve时传的的参数。运行这段代码,会在2秒后输出“执行完成”,紧接着输出“随便什么数据”。这时我们就会明白,then里面的函数就跟我们平时的回调函数一个意思,能够在run这个异步任务执行完成之后被执行。这就是Promise的作用了,简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。你可能会想,我写个回调函数不是照样能实现Promise函数的功能吗,但是如果是多次回调,你就会发现callback回调不能满足我们的需求了,而then方法可以进行链式操作,很好地解决了回调地狱的问题。
链式操作的用法
function run(){
var p=new Promise(function(resolve,reject){
setTimeout(function(){
onsole.log("执行完成");
resolve("随便什么数据");
},1000);
});
return p;
}
run()
.then(function(data){
console.log(data);
return run();
})
.then(function(data){
console.log(data);
return run();
})
.then(function(data){
console.log(data);
});
运行之后,每隔两秒输出每个异步回调中的内容,在runAsync2中传给resolve的数据,能在接下来的then方法中拿到。运行结果如下:
执行完成
随便什么数据
执行完成
随便什么数据
执行完成
随便什么数据
你也可以直接return "hello world",会输出hello world,但其后面不能继续使用then方法。
reject的用法
上面的例子都是“执行成功”的resolve回调,下面我们来看一下reject的用法:
function getNum(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*10);
if(num<6){
resolve(num);
}
else{
reject('超出范围');
}
}, 2000);
});
return p;
}
getNum()
.then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason){
console.log('rejected');
console.log(reason);
}
);
getNum函数执行时,若得到的数字小于6,则认为成功了,调用resolve方法将Promise的状态置为fullfiled,输出得到的数字;否则调用reject的方法将Promise的状态置为rejected,输出“超出范围”。
catch的用法
catch方法和reject实现的效果是一样的,但它还用另外一个用法:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了,那么并不会报错卡死js,而是会进到catch方法中。示例如下:
getNum()
.then(function(data){
console.log('resolved');
console.log(data);
console.log(somedata); //此处的somedata未定义
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
在resolve的回调中,我们console.log(somedata);而somedata这个变量是没有被定义的。一般情况下,代码运行到这里就直接在控制台报错了,不往下运行了。但是在Promise中,会得到这样的结果:
resolved
2
rejected
ReferenceError: somedata is not defined
all的用法
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。示例如下:
function run1(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步任务1执行完成');
resolve('随便什么数据1');
}, 1000);
});
return p;
}
function run2(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步任务2执行完成');
resolve('随便什么数据2');
}, 2000);
});
return p;
}
Promise
.all([run1(), run2()])
.then(function(results){
console.log(results);
});
用Promise.all来执行,all接收一个数组参数,里面的值最终都返回Promise对象,等到所有的Promise对象都执行完才会进入then方法,而异步操作的数据都保存在一个数组中,以参数的形式传给then方法,输出结果如下:
异步任务1执行完成
异步任务2执行完成
["随便什么数据1","随便什么数据2"]
race的用法
race是赛跑的意思,race方法是以执行速度快的异步操作回调。如用race给某个异步请求设置超时时间,并且在超时后执行相应的操作:
function request(){
var p=new Promise(function(resolve,reject){
var img=new Image();
img.onload=function(){
resolve(img);
}
img.src="XXXX";
});
return p;
}
function timeout(){
var p=new Promise(function(resolve,reject){
setTimeout(function(){
reject("图片请求超时");
},5000);
});
return p;
}
Promise
.race([request(),timeout()])
.then(function(results){
console.log(results);
})
.catch(function (reason){
console.log(reason);
});
Promise的race方法会同时调用两个方法,若5秒内request函数调用成功,则调用resolve方法把Promise的状态置为fullfiled,进入then方法;否则会执行timeout函数,则调用reject方法把Promise的状态置为rejected,进入catch方法。示例中,因为找不到图片,输出结果如下:
Failed to load resource: net::ERR_FILE_NOT_FOUND
图片请求超时
Promise构造函数的常用方法到这里基本上就说完了,后面将讲述javascript的闭包现象。敬请期待!