angularjs系列之轻松使用$q进行异步编程

 第一部分关于js中的异步编程

  异步编程简单的说就是你写了一段代码,但他不会按照你书写代码的顺序立即执行,而是等到程序中发生了某个事件(如用户点击了某个按钮,某个ajax请求得到了响应)才去执行这段代码,而且这段代码可能执行一次(如一个ajax请求得到了响应)、也可能执行很多次或者不执行(一个按钮被点击了许多次或者0次)这就是所谓的异步编程。

  有两种异步程序模式单次执行模式监听执行模式。像ajax请求这样的就是属于单次执行模式,请求、回调只会进行一次。像事件绑定就属于监听执行模式,只要事件发生回调就可以不断的执行。但是不管是单次执行模式还是监听执行模式在js程序中的共同点都是保存着一个函数引用(这个引用的表现形式就回调函数),在某个事件发生后开始执行这个函数引用中的代码。

  下面给出这两种模式的整体模型图:

  异步执行体:包含异步执行代码(或者异步动作)和状态,状态不可逆。

  回调执行体:包含回调执行代码和状态,状态不可逆。

  两种执行体是依靠异步执行体发送信号通信。

  监听执行模式和单次执行模式的区别:监听模式中会有多个异步执行体和回调执行体副本,且每个异步执行体副本关联一个回调执行体副本。多个副本的这两种执行体的执行代码是一样的,唯一区别的就是每个副本的状态不同。

  代码举例:

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

//单次执行模式:

funtion a(b) {

       console.log(“a process”);

       b();

};

function
b() {

       console.log(“b process”);

};

a(b); //发送信号

//监听执行模式(这里直接使用jquery):

$(“#button”).bind(“click”, function() {

       console.log(“click callback”);

});

$(“#button”).trigger(“click”); //发送信号

第二部分关于promise模式的异步编程

  上面就是异步编程的两种形式,由于我们的$q是解决第一种模式中存在的问题的,所以这里就讨论讨论单次执行模式中存在的问题。你可以设想这么一种场景,当你要在很多个ajax请求响应完成后做一件事情,你用现有的js的回调方式,会不会发现回调的层次很深、代码十分混乱。而然我们promise模式的异步编程方式就能很好的管理这些单次执行模式下的代码,使你的代码书写起来更加优雅,说白了promise不产生新的东西只是一个语法糖使你编写出更加优雅的异步程序代码。

  那promise模式到底是什么样的呢,说白了就是把把我上面的单次执行模式图抽象化了,用一个defer对象(延期对象)代表异步执行体,用一个promise对象(承诺对象)代表回调执行体,这个defer对象可以发送消息,promise接受消息,然后执行相应的回调函数。Promise就是异步执行体和回调执行体之间的桥梁,这样的好处是异步执行体和回调执行体这种模型很好的对异步动作和回调动作进行了解耦。你可以在promise上面好好的操纵你的回调执行体,而只是接受一个来自defer发送的参数。

  这里还不能很好的体现出promise模式的优势,而她真正的优势是在这种模型下扩充的api使其发挥了真正的强大作用。比如说promise对象的then方法,这个方法就是支持异步链式编程最重要的方法,他也是使代码更加优雅最重要的方法。还有比如说all接收一个promise数组返回一个新的promise,当前面的所有promise状态都完成之后这个新的promise才能完成,这个很适合多个ajax后处理某些事情。不过可能你还不能明白,下面在介绍$qAPI的时候有详细的介绍。

第三部分
$q
服务的API详解

  下面我们通过讲解$q的API让你更多的了解promise异步编程模式。$q是做为angularjs的一个服务而存在的,只是对promise异步编程模式的一个简化实现版,源码中剔除注释实现代码也就二百多行,下面开始介绍$q的API。

defer对象(延迟对象)可以通$q.defer()获取,下面是defer对象的api:

 方法:

resolve(value):向promise对象异步执行体发送消息告诉他我已经成功完成任务,value即为发送的消息。

reject(value):
向promise对象异步执行体发送消息告诉他我已经不可能完成这个任务了,value即为发送的消息。

notify(value):
向promise对象异步执行体发送消息告诉他我现在任务完成的情况,value即为发送的消息。

  这些消息发送完promise会调用现有的回调函数。

属性:

promise即与这个defer对象的承诺对象。

  从上可以看出defer主要是用来发送消息的。

  promise对象可以通过defer.promise获取,下面是promise对象的api:

  方法:

  then(successCallback,errorCallback,notifyCallback):参数为不同消息下的不同回调函数,defer发送不同的消息执行不同的回调函数,消息作为这些回调函数的参数传递。返回值为回一个promise对象为支持链式调用而存在。当第一个defer对象发送消息后,后面的promise对应的defer对象也会发送消息,但是发送的消息不一样,不管第一个defer对象发送的是reject还是resolve,第二个及其以后的都是发送的resolve,消息是可传递的。

  catch(errorCallback):then(null,errorCallback)的缩写。

  finally(callback):相当于then(callback,callback)的缩写,这个finally中的方法不接受参数,却可以将defer发送的消息和消息类型成功传递到下一个then中。

  代码举例:

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

function
f1(num) {

       document.write("success:"
+ (num++) + "<br/>");

       return
num;

}

function
f2(num) {

       document.write("errror:"
+ (num++) + "<br/>");

       return
num;

}

var
defer = $q.defer();

var
promise = defer.promise;

//方式1

// promise.then(f1,f2).then(f1,f2);

// 方式2

// promise.then(f1,f2);

// promise.then(f1,f2);

// 方式3

// promise.then(f1,f2).then(f1,f2);

// promise.catch(f2);

// promise.finally(f2);

//方式4

// promise.finally(f2).then(f1,f2);

defer.reject(1);

方式1的结果:

errror: 1

success: 2

方式2的结果:

errror: 1

errror: 1

方式3的结果:

errror: 1

errror: 1

error: NaN

success: 2

方式4的结果:

Error: NaN

Error: 1  

  现在继续$q的api:

  方法:

  defer():用来生成一个延迟对象 var defer =$q.defer();

  reject():参数接收错误消息,相当于在回调函数中抛出一个异常,然后在下一个then中调用错误的回调函数。

  代码举例:

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

var
defer = $q.defer();

var
promise = defer.promise;

promise.then(function() {

       return
$q.reject("success error");

}, function() {

       return
$q.reject("error error");

}).then(function(info) {

       document.write("s:"
+ info + "<br/>");

}, function(info) {

       document.write("e:"
+ info + "<br/>");

});

//方式1

// defer.reject(1);

//方式2

// defer.resolve(1);

方式1运行结果

e: error error

方式2运行结果

e: success error

  

  all()参数接收为一个promise数组,返回一个新的单一promise对象,当这些promise对象对应defer对象全部解决这个单一promise对象才会解决,当这些promise对象中有一个被reject了,这个单一promise同样的被reject了。

  代码举例:

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

var
defer1 = $q.defer();

var
promise1 = defer1.promise;

promise1.then(function(num) {

              console.log("success"
+ num);

       },

       function(num) {

              console.log("error"
+ num);

       });

var
defer2 = $q.defer();

var
promise2 = defer2.promise;

promise1.then(function(num) {

              console.log("success"
+ num);

       },

       function(num) {

              console.log("error"
+ num);

       });

var
promise3 = $q.all([promise1, promise1]);

promise3.then(function(num) {

       console.log("s:"
+ num);

}, function(num) {

       console.log("e:"
+ num);

});

//方式1

// defer1.resolve(1);

// defer2.resolve(1);

//方式2

//defer1.reject(1);

方式1的结果:

success1

success2: 1

s: 1,

1

方式2的结果:

error1

e: 1

  

  when():接收第一个参数为一个任意值或者是一个promise对象,其他3个同promise的then方法,返回值为一个promise对象。第一个参数若不是promise对象则直接运行success回调且消息为这个对象,若为promise那么返回的promise其实就是对这个promise类型的参数的一个包装而已,被传入的这个promise对应的defer发送的消息,会被我们when函数返回的promise对象所接收到。

  代码举例:

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var
promise = $q.when(1, function(num) {

       console.log(‘s‘
+ num);

}, function() {

       console.log(‘e‘);

});

var
defer1 = $q.defer();

var
promise1 = defer1.promise;

var
promise2 = $q.when(promise1, function(num) {

       console.log(‘s‘
+ num);

}, function() {

       console.log(‘e‘);

});

defer1.reject(1);

运行结果:

s1

e

  对上面还有一个注意事项就是defer对象发送消息不会立即执行的,而是把要执行的代码放到了rootScope的evalAsync队列当中,当时scope.$apply的时候才会被promise接收到这个消息。

  到这里$q服务全部介绍完了,对于angular中的then的链式调用中如果defer发送的reject的那么只有第一个promise是reject的回调,其他的都是resolve的回调这里多少觉得是不合适的,不知道是个bug还是就是这样设计?$q只适合单次执行模式,不知道是否适合扩展成监听执行模式?这都是大家值得思考的问题。

时间: 2024-10-11 18:43:25

angularjs系列之轻松使用$q进行异步编程的相关文章

Promise和异步编程

前面的话 JS有很多强大的功能,其中一个是它可以轻松地搞定异步编程.作为一门为Web而生的语言,它从一开始就需要能够响应异步的用户交互,如点击和按键操作等.Node.js用回调函数代替了事件,使异步编程在JS领域更加流行.但当更多程序开始使用异步编程时,事件和回调函数却不能满足开发者想要做的所有事情,它们还不够强大,而Promise就是这些问题的解决方案 Promise可以实现其他语言中类似Future和Deferred一样的功能,是另一种异步编程的选择,它既可以像事件和回调函数一样指定稍后执行

angularjs 系列之$q和promise

还是同一个项目,在项目中,发现多个controller之内有一个共同的服务器请求,当时只是不断的重复使用,如今,现在项目结束,代码开始走向了优化迭代的阶段: 首先,我的思路是把这个共同的请求,从controller里抽出来,做成一个服务,然后在需要的controller里注入: 第一个问题是请求服务器数据: var app = angular.module('testApp',['ui.bootstrap']); app.factory('myService',['$http','$q',fun

深究angularJS系列 - 第三弹

深究angularJS系列 - 初识 深究angularJS系列 - 第二弹 深究angularJS系列 - 第三弹,我们一起深入探究angular的服务和自定义指令O(∩_∩)O~~ Angular服务 $http: $http是angular中的一个核心服务; $http利用浏览器的xmlhttprequest或JSONP与远程HTTP服务器进行交互; $http的支持多种method的请求,get.post.put.delete.jsonp等. 下面通过JSONP方法进行$http服务的使

深究angularJS系列 - 第二弹

深究angularJS系列 - 第二弹,在初步了解了Angular的基础上,进一步的针对Angular的控制器和作用域问题深入探究O(∩_∩)O~~ Angular控制器 控制器(Controller)的理解 控制器是对view的抽象,用来接收view的事件,响应view的请求: 控制器包含view的静态属性和动态的方法: 控制器与view是一对一的关系. 控制器(Controller)的结构 1 .controller("控制器的名字",function($scoppe){ 2 ..

C#网络编程系列文章(一)之Socket实现异步TCPserver

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列文件夹 C#网络编程系列文章(一)之Socket实现异步TCPserver C#网络编程系列文章(二)之Socket实现同步TCPserver C#网络编程系列文章(三)之TcpListener实现异步TCPserver C#网络编程系列文章(四)之TcpListener实现同步TCPserver C#网络编程系列文章

WPF技术触屏上的应用系列(五): 图片列表异步加载、手指进行缩小、放大、拖动 、惯性滑入滑出等效果

原文:WPF技术触屏上的应用系列(五): 图片列表异步加载.手指进行缩小.放大.拖动 .惯性滑入滑出等效果 去年某客户单位要做个大屏触屏应用,要对档案资源进行展示之用.客户端是Window7操作系统,54寸大屏电脑电视一体机.要求有很炫的展示效果,要有一定的视觉冲击力,可触控操作.当然满足客户的要求也可以有其它途径.但鉴于咱是搞 .NET技术的,首先其冲想到的微软WPF方面,之前对WPF的了解与学习也只是停留在比较浅的层面,没有进一步深入学习与应用.所以在项目接来以后,也就赶鸭子上架了,经过努力

AngularJS系列之总结

AngularJS深入的系列就是这九篇博客了,把我以前在项目中应用到的和自己学习的都总结在了里面.为了更方便的看,把我写的AngularJS系列的博客都列到下面.之后就开始学习ionic:html5移动开发框架,它是基于AngularJS的移动开发框架.希望大家多多关注我的博客,多多推荐. AngularJS之站在jQuery的肩膀上: http://www.cnblogs.com/xuema/p/4335180.html AngularJS应用开发思维之1:声明式界面  http://www.

C#基础系列——异步编程初探:async和await

前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了异步并行变成带来了很大的方便.异步编程涉及到的东西还是比较多,本篇还是先介绍下async和await的原理及简单实现. C#基础系列目录: C#基础系列——Linq to Xml读写xml C#基础系列——扩展方法的使用 C#基础系列——序列化效率比拼 C#基础系列——反射笔记 C#基础系列——At

异步编程系列第04章 编写Async方法

p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提高下英文,用我拙劣的英文翻译一些重要的部分,纯属娱乐,简单分享,保持学习,谨记谦虚. 如果你觉得这件事儿没意义翻译的又差,尽情的踩吧.如果你觉得值得鼓励,感谢留下你的赞,愿爱技术的园友们在今后每一次应该猛烈突破的时候,不选择知难而退.在每一次应该独立思考的时候,不选择随波逐流,应该全力以赴的时候,不选择尽力而