function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log("执行完成");
resolve("随便什么数据");
}, 2000);
});
return p;
}
runAsync()
这时候你应该有两个疑问:1.包装这么一个函数有毛线用?2.resolve("随便什么数据");这是干毛的?
在我们包装好的函数最后,会return出Promise对象,也就是说,执行这个函数我们得到了一个Promise对象。
还记得Promise对象上有then、catch方法吧?这就是强大之处了,看下面的代码:
runAsync().then(function(data){
console.log(data);
//后面可以用传过来的数据做些其他操作
//......
});
在runAsync()的返回上直接调用then方法,then接收一个参数,是函数,并且会拿到我们在runAsync中调用resolve时传的的参数。
运行这段代码,会在2秒后输出“执行完成”,紧接着输出“随便什么数据”
这时候你应该有所领悟了,原来then里面的函数就跟我们平时的回调函数一个意思,能够在runAsync这个异步任务执行完成之后被执行。
这就是Promise的作用了,简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
你可能会不屑一顾,那么牛逼轰轰的Promise就这点能耐?我把回调函数封装一下,给runAsync传进去不也一样吗,就像这样:
function runAsync(callback){
setTimeout(function(){
console.log("执行完成");
callback("随便什么数据");
}, 2000);
}
runAsync(function(data){
console.log(data);
});
效果也是一样的,还费劲用Promise干嘛。那么问题来了,有多层回调该怎么办?如果callback也是一个异步操作,而且执行完后也需要有相应的回调函数,
该怎么办呢?总不能再定义一个callback2,然后给callback传进去吧。而Promise的优势在于,可以在then方法中继续写Promise对象并返回,
然后继续调用then来进行回调操作。
链式操作的用法
所以,从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,
它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的:
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
这样能够按顺序,每隔两秒输出每个异步回调中的内容,在runAsync2中传给resolve的数据,能在接下来的then方法中拿到。运行结果如下:
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
异步任务3执行完成
随便什么数据3
猜猜runAsync1、runAsync2、runAsync3这三个函数都是如何定义的?没错,就是下面这样:
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log("异步任务1执行完成");
resolve("随便什么数据1");
}, 1000);
});
return p;
}
function runAsync2(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log("异步任务2执行完成");
resolve("随便什么数据2");
}, 2000);
});
return p;
}
function runAsync3(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log("异步任务3执行完成");
resolve("随便什么数据3");
}, 2000);
});
return p;
}
在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了,比如我们把上面的代码修改成这样:
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return "直接返回数据"; //这里直接返回数据
})
.then(function(data){
console.log(data);
});
那么输出就变成了这样:
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
直接返回数据
到这里,你应该对“Promise是什么玩意”有了最基本的了解。那么我们接着来看看ES6的Promise还有哪些功能。我们光用了resolve,
还没用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的回调。所以我们能够分别拿到他们传过来的数据。多次运行这段代码,你会随机得到下面两种结果:
resolved 1 或者 rejected 数字太大了
到这里已经说完了Promise 常用的内容了,当然还有 catch ,all, race 的用法,以后再继续说吧。