1.前言:
如我们所知道的javascript是一门单线程语言,不像java语言中有多线程的机制,前不久做项目的时候,需要在前端使用js进行一些列的ajax异步请求,这些请求之间有一种关系,就是下一次请求的参数是上一次请求的结果,在javaweb端我们可以很容易的用同步请求的方式解决,阻塞线程知道函数执行完,但是在前端的ajax中就得不断的嵌套函数,十分的恶心,好在最后找到了Promise这个好东西,并将学习成果总结下来。
2.Promise:
2.1:Promise 的resolve 和reject
就如其名一样,Promise类似于某种承诺,当我们在特定的时候告诉它应该干什么(异步请求成功后),它就会在接受到结果后第一时间告诉我们,类似于java中的回调函数,而且它可以使用一种链式的结构,将我们的异步请求连接起来,只有当我们前面的异步请求成功后,后面的异步函数才会执行。
举个栗子:
这里我们简单的模拟了一个异步请求,在两秒后我们可以看到alert显示了我们的信息,这看起来貌似没有什么蛋用啊,可是这只是一个简单的演示,如果我们的异步请求多了就可以看出它的威力了,解析来我们就来一个三个异步的栗子:
上面的代码看起来有点乱啊,其实就是三个延迟函数而已,我们可以在控制台上看见间隔2秒、1秒、1秒后我们的结果按顺序的打印出来了,实际情况中我们并不会这样写,这样多来几次有懵逼了,我们最终的代码会像如下这样:
第一个异步请求的: promise.then(function(result){
return promise2;
}).then(function(result2){
reutrn promise3;
})...//N个一条链式的结构
那这就有一个疑问了,网络请求不都是成功的,可能是失败的,我们不希望在请求失败后依然去调用下一个请求,这是我们就需要Promise函数的第二个方法了,Promise.reject();用法和第一个成功回调一样,唯一的区别是回调的函数有一点差异,下面就举一个栗子:
这里我们定义了一个假的异步请求,我们随机一个返回值,如果大于5,我们就认为成功,alert success回调,如果失败就在控制台打印。大家就发现了,then()函数的第二个参数就是失败的回调,一个promise要么成功要么失败。
以上就是Promise的简单使用,我们再来看几个高级一点的例子:
假设有如下场景,我们查询两种分开的表,前一张表的结果是后一张表的参数,而且后一次查询还不止一次,打个比方:我们去买苹果,买苹果就是我们的第一个请求,但是有很多种的苹果,我们为了确定哪个好吃我们需要每种都试吃一遍,然后选择一种,当然如果在现实中,可能我们这样做草都一米高了。这时候前面的方法就不适用了,我们需要一个新的方法。
2.2 Promise的all:
Promise.all()函数就是一个解决上诉问题的方法,它接受一个promise的数组,当这些promise都执行完后或则有一个失败的时候回调。
我们定义两个成功的回调,在两个异步执行完成之后,我们会得到一个保存结果的数组,结果数组中的结果与之前的参数的promise对应,就是p3的结果是result[0],依次类推。
那么在如果我们的异步请求中如果有一个出错的会怎么样了?
我们将上诉方法稍微改造下,让第二个异步失败,此时我们可以在控制台上输出了four error,并没有three的影子,这就是all的特点,要么全部成功,要么在第一个error出停止。我们接着看下一个函数。
2.3 Promise的race:
这个方法比较有意思,Promise.race(),这个方法也是接受一个promise数组作为参数,返回一个promise,但是它就如它的名字一样,他只返回最先执行完的第一个promise的结果。
2.4Promise的catch:
在上面我们说了promise可以将一系列的异步请求串起来,此时就有一个问题,如果我们不想在每个异步请求的回调里去检测失败,只关心最终的结果,此时我们就可以使用catch()函数,它可以捕获我们执行调用链中的reject和exception,写法如下:
promise.then(function(){
return promise;
}).then(function(){
//do something
}).catch(function(error){
})
这里需要注意的就是,当我们回调链中有一个函数接受了错误的回调,那么catch函数就不会被调用了。以上就是javascript自带的Promise,下面我们看一个Angular1.x中的Promise机制。
3.Angular中的$q
在Angular1.x中我们可以在controller中注入$q使用Promise函数下面就简单介绍一下。
//声明一个模块
var app=angular.module('appM',[]);
//定义一个控制器并注入我们的$scope和$q
app.controller('myCtrl',['$scope','$q',function($scope,$q){
//定义一个异步请求方法:
$scope.httpRequest=function(param){
var defer=$q.defer();
//异步操作
if(suc){
defer.resolve();
}else{
defer.reject();
}
return defer.promise;
}
$scope.httpRequest().then(function(suc){
//成功
},function(er){
//失败
})
}])
Angular中的$q还有
- when():一般在参数不确定的时候使用
- all():和javascript中的效果一样
- finally():类似于java中的try catch最后的finally方法。