js,jquery then,angular.js $q 异步编程

来源:互联网 发布:debian java 编辑:程序博客网 时间:2024/05/22 07:09

我们知道,JavaScript语言的执行环境是单线程的。


所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。

这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。
为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;
"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
通常,我们执行异步的方法是通过回调函数,如:
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. function f1(){  
  2.     setTimeout(function () {  
  3.         //doSomething  
  4.         setTimeout(function () {  
  5.             //doSomething  
  6.             setTimeout(function () {  
  7.                 //doSomething  
  8.             },300)  
  9.         },200)  
  10.     },100)  
  11. }  
这样书写固然简单,但是问题也来了,金字塔类型的接口不利于代码阅读与维护,如果,代码写成这样,会不会更利于阅读维护呢?
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. f1  
  2.     .then(function () {  
  3.   
  4.     })  
  5.     .then(function () {  
  6.   
  7.     })  
  8.     .then(function () {  
  9.   
  10.     });  
即将原来的回调金字塔式改写成链式,这样我们就可以很清楚的看清楚每个方法执行的是什么了。

因此CommonJS提出一种Promise规范,目的是为了异步编程提供统一的接口

Jquery中的promise

在jquery1.5版本后,引入了promise对象,实现了基本的promise,如果你在jquery1.5以上版本,可以发现 原来的ajax方法还可以这样用
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. var jqxhr = $.ajax( "example.php" )  
  2.     .done(function() {  
  3.         alert( "success" );  
  4.     })  
  5.     .fail(function() {  
  6.         alert( "error" );  
  7.     })  
  8.     .always(function() {  
  9.         alert( "complete" );  
  10.     });  

将原来嵌入内部的success,error方法变为链式调用,这是因为在1.5版本,ajax方法进行了封装,$.ajax()获得的是一个$.Deferred对象。
因此,我们可以知道Deferred对象可以完成链式异步调用,

因此,我们可以将这样的形式
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. function wait(resolve){  
  2.     var a=1;  
  3.     resolve(a);  
  4. }  
  5.   
  6. wait(function (data) {  
  7.     alert(data)  
  8. });  
改写成
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. function wait() {  
  2.        var def = $.Deferred();           //获取deferred对象  
  3.        def.resolve(1); // 改变Deferred对象的执行状态    ,resolve为成功状态 //当收到resolve时,变执行then方法  
  4.        setTimeout(tasks, 1000);  
  5.        return def.promise();  
  6.    }  
  7.   
  8.    $.when(wait())  
  9.            .then(function (data) {  
  10.                alert(data);   //1  该值有resolve(1) 中的1得来  
  11.            })  

时候,我们需要不止一部,可能需要多个步骤,那么只需要 在前一个then的回调中签返回值就可,从这里我们能够看出 .then()方法返回的也是一个deferred.promise对象
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. $.when(wait())  
  2.         .then(function (data) {  
  3.             alert(data);  
  4.             return data+1;  
  5.         })  
  6.         .then(function (data) {  
  7.             alert(data);  
  8.         });  

angular中的promise

同上,在angular中,我们也支持promise异步方法,他使用了一个内置对象$q
具体使用代码如下:
[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>var getData = function () {  
  2.             var defer = $q.defer();       //同jquery $.Deferred  
  3.             $timeout(function () {  
  4.                 defer.resolve(1);         //改变成功状态  
  5.             }, 1000);  
  6.   
  7.             return defer.promise;  
  8.         };  
  9.         getData()  
  10.                 .then(function (data) {       //getData执行完成后  
  11.                     alert(data);                  //1  
  12.                     return data+1;               
  13.                 })  
  14.                 .then(function (data) {  
  15.                    alert(data);                    //2  
  16.                 });  
注意,angular还有一个when方法,他和jquery中的$.when()还是有一些区别的,如下

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:Microsoft YaHei;">var def = $q.defer();  
  2.         var q=$q.when(12);  
  3.         q.then(function (data) {  
  4.             alert(data); //12  
  5.         });</span>  
angular 中$q.when()方法是将里面的参数封装成一个$q.defer().promise对象,因此 可以通过then方法获取when里面的值
而Jquery中,$.when()接收的是一个deferred对象,不满足promise/A规范。

总结

其实在promise/A规范中还有很多关于promise的定义,如all() 、spread() 、race() 、denodeify() ,如果想了解 promise 的更多功能,我建议诸位看看 Bluebird 函数库的 API。本文只记录了最简单的形式,如果有什么问题,望指正,谢谢。

推荐阅读 

JavaScript Promise 探微
1 0
原创粉丝点击