angularjs的异步处理机制

       JS的常规请求方式是同步的,这样容易造成阻塞,而后来改进引入了ajax来处理异步请求,同样是对XMLHTTPRequest的封装,angularjs也提供了异步处理机制。怎样理解异步请求呢?

现在寒冬将至,我需要一套被子,以度过寒冬。于是我向被服店发起一个请求,那就是替我定制一套被服。当然定制的话需要一定的时间来生产,我并不着急,放下定金我就走了,并告诉店主,做好了给我送过去,并留下地址和联系方式。那么我就可以去做其他的事情,我不可能因为这点事情而耽误生活继续。这就是简单的我发起了一个异步请求,也可以称为可延期的请求。但是我不会无限期的等待,所以我需要跟店主确认需要多长时间来处理这个事情,显然我不可能等过整个寒冬,那这个被子对我来说将毫无意义。所以我需要店主的一个承诺,一个promise。店主将承诺时间告诉我这就叫做$q.defer延期请求,并可以通过某种回执来时刻关注进展情况。这种就叫做deferred,延期事件。

在这个请求的过程中,我们可以想到有很多的情况,比如,由于机器损坏或者被子的原料不够,需要从外地进货,不能按期完成,那么在处理这个请求的过程中,店主就可以发起reject回执,从而来减少我的等待,你做不了,我就需要得到一个回执,然后我需要找其他的店铺来处理这种事情。当然这种reject不单单包含回执消息还可以包含其他的东西,你比如定金回退,违约金回退,以及原因等消息。如果这个请求事件一直进行的比较顺利,店家又比较贴心,那么他会实时或者每天,每周给我发个消息,来汇报被子的进展情况,这就叫通知notify。最后,店家如期的将被子做好,送到我住的地方,我给他个好评,整个请求的过程完满结束,那就是处理完成了,我们称为resolve。

从上面我们可以看到,一次异步请求应当包含但不仅包含这三个方面。看一下如何来使用这种异步方式。

1.$http

在谈及$q之前,先来了解一下$http。$http是angularjs封装的http应用,用于同服务器请求,类似于ajax的一种封装,我们来看看它的形式,当然既然是angularjs提供的,那么我们需要首先引入$http这种服务,才能正常的使用。

$http({
                method:'GET',
                url:'api/ham/guest/account/getAccountList'
            });
看起来跟ajax的很相似,那么他本身是个什么东西呢?我们来打印一下:

var promise = $http({
                method:'GET',
                url:'api/ham/guest/account/getAccountList'
            });
            console.log("promise",promise);

可以看到输出结果如下,它包含了成功success,失败error的回调函数,并且包含了header,状态码,以及一些请求的数据,这也就是一个promise对象。



来看一下,这几个方法有什么不同的地方:

var promise = $http({
                method:'GET',
                url:'api/ham/guest/account/getAccountList'
            });
            promise.success(function (data) {
                console.log("data",data);
            });
            promise.then(function (data) {
                console.log("success",data)
            });
            promise.error(function (data) {
                console.log("error",data)
            })

我们看一下打印结果,从这里面我们可以明显看出,success中的数据就是我们想要的服务端返回的数据,而在then中我们发现他不但包含了我们的服务端的数据,还包含状态码以及header部分,当然由于状态码是200,说明这次请求是成功了,所以不会打印error中的东西:


2.$q

$q是angularjs封装的一种promise的实现,通过$q来创建promise。其实在上面的例子中我们就知道了一个promise的内容,那么由$q来创建的promise有什么不同呢?

function getList() {
            var deferred = $q.defer();
            console.log("deferred",deferred);
            $http.get(ovHttp.proxy('api/ham/guest/account/getAccountList'))
                .success(function (data, status) {
                    //if (data.result == 'success') {
                    deferred.resolve(data);
                    //}
                    //else if (data.result != 'success') {
                    //    //handleError();
                    //}
                });
            console.log("deferred.promise",deferred.promise);
            return deferred.promise;
        }



从上面可以看出来,我们通过$q创建的deferred对象中就包含一个promise,promise中的方法和属性跟$http返回的一致。可以看出多出来的就是,notify(通知),reject(拒绝),resolve(解决),这三个回调函数,我们在success中会使用deferred.resolve来处理返回的数据,而在error中使用deferred.reject来处理数据。处理之后将返回一个promise对象,不管成功失败。
那么promise提供的方法promise.then(successFunc,errorFunction,notifyFunc),来处理异步不同的结果。
successFunc将会在resolve执行之后被调用。
errorFunc将会在reject之后被调用。
notifyFunc将会在notify之后被调用。
catch回调负责处理其他的异常处理。
finally回调负责释放资源或者刷新操作等。

$q创建promise有两种方式。

2.1 第一种方式

service中:
function testQ(){
            return $q(function (resolve, reject) {
                $timeout(function () {
                    if(1==1){
                        resolve("resolve");
                    }else{
                        reject("reject");
                    }
                },1000)
            })
        }

controller中:

amGuestAccountService.testQ().then(
                    function (data) {
                        console.log("success",data);
                },
                    function (data) {
                        console.log("error",data);
                })
                .catch(function (data) {
                    console.log("error",data);
                });

看一下执行结果:
换一种写法:

function testQ(){
            return $q(function (resolve, reject) {
                $timeout(function () {
                    if(1!=1){
                        resolve("resolve");
                    }else{
                        reject("reject");
                    }
                },1000)
            })
        }
输出结果:


2.2 第二种方式

我们来看看另外一种创建方式:
service中:
function getList() {
            var deferred = $q.defer();
            console.log("deferred",deferred);
            $http.get(ovHttp.proxy('api/ham/guest/account/getAccountList'))
                .success(function (data, status) {
                    deferred.resolve(data);
                }, function (data,status) {
                    deferred.reject("reject the request");
                });
            return deferred.promise;
        }


controller中:
amGuestAccountService.getList().then(function (data) {
                    console.log("resolve",data);
                }, function (data) {
                    console.log("reject",data)
                }, function (data) {
                    console.log("notify",data);
                });


2.3 promise的其他方法

在处理这种异步操作的时候,有时我们会碰到这种需求。我可能觉得北京今年的天气特别冷,比以往都要冷,
所以一张被子可能不足以御寒,那么我就需要再去店里定制另一张被子,当然我也许会多订一些比如被罩,枕巾
之类的东西,那我我就会在请求一次,那么我陆陆续续的下了好多订单,我不会去选择记住每一个的请求和时间,
我会采取一次性制作完成再统一给我送过来,这样我就不需要去关注某一个了。angualrjs的$q也支持这种操作
它可以将你的多个promise都在all里面处理。也就是说$q.all可以接受一个数组的形式。当所有的promise都resolve
,它会将他们都存到自己的resolve中,然后统一返回。当然如果有一个出现reject的时候,他也会把reject存到自己
的reject中,但只会有一个,不会出现多个的形式。

function q1() {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.notify("1 notify");
                    if (1==1) {
                        deferred.resolve("1 resolved");
                    } else {
                        deferred.reject("1 reject");
                    }

                }, 1000);

                return deferred.promise;
            }

            function q2() {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.notify("2 notify");
                    if (1==1) {
                        deferred.resolve("2 resolved");
                    } else {
                        deferred.reject("2 reject");
                    }

                }, 1000);

                return deferred.promise;
            }


$q.all([q1(),q2()]).then(function (data) {
                    console.log("resolve",data);
                }, function (data) {
                    console.log("reject",data)
                }, function (data) {
                    console.log("notify",data);
                });

输出结果:



function q1() {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.notify("1 notify");
                    if (1==1) {
                        deferred.resolve("1 resolved");
                    } else {
                        deferred.reject("1 reject");
                    }

                }, 1000);

                return deferred.promise;
            }

            function q2() {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.notify("2 notify");
                    if (1!=1) {
                        deferred.resolve("2 resolved");
                    } else {
                        deferred.reject("2 reject");
                    }

                }, 1000);

                return deferred.promise;
            }
            function q3() {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.notify("3 notify");
                    if (1!=1) {
                        deferred.resolve("3 resolved");
                    } else {
                        deferred.reject("3 reject");
                    }

                }, 1000);

                return deferred.promise;
            }
            function q4() {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.notify("4 notify");
                    if (1==1) {
                        deferred.resolve("4 resolved");
                    } else {
                        deferred.reject("4 reject");
                    }

                }, 1000);

                return deferred.promise;
            }

在上面,我定义了四个promise,其中有两个是reject的,那么我们来看看输出结果是怎么样的呢?

哎呦,就输出一个。由此可以看出,只要是有一个reject的,那么就只会输出一个reject结果,不管你其他的
promise是否执行resolve的,而且多个reject的是不会叠加的,只会输出第一个reject。
相关文章
相关标签/搜索