HTML5资讯

当前位置: HTML5技术网 > HTML5资讯 > 短小强悍的JavaScript异步调用库

短小强悍的JavaScript异步调用库

       我们知道,在浏览器中的 JavaScript 绝大部分的操作都是异步的(asynchronous),所以我们一直都需要使用回调方法,而有时不免陷入回调的泥淖而欲死欲仙。

  假设我们有两个 functions ,我们顺序地在一个后面执行完后调用另一个。他们都操作同一个变量。第一个设置它的值,第二个使用它的值。

  1. var value;  
  2. var A = function() {  
  3.     setTimeout(function() {  
  4.         value = 10;  
  5.     }, 200);  
  6. }  
  7. var B = function() {  
  8.     console.log(value);  
  9. }
复制代码        那么,现在如果我们运行 A();B(); 我们将在控制台看到输出为 undefined . 之所以会这样是因为 A 函数使用了异步方式设置 value 。我们能做的就是传一个回调函数给A,并让函数A在执行完后执行回调函数。

  1. var value;  
  2. var A = function(callback) {  
  3.   setTimeout(function() {  
  4.     value = 10;  
  5.     callback();  
  6.   }, 200);  
  7. };  
  8. var B = function() {  
  9.   console.log(value);  
  10. };  
  11. A(function() {  
  12.   B();  
  13. });
复制代码       这样确实有用,但想象一下加入我们需要运行5个或更多方法时将会发生什么。一直传递回调函数将会导致混乱和非常不雅观的代码。
       好的解决办法是写一个工具函数,接受我们的程序并控制整个过程。让我们先从最简单的开始:
  1. var queue = function(funcs) {  
  2.     // 接下来请看,董卿???  
  3. }
复制代码      接着,我们要做的是通过传递A和B来运行该函数 - queue([A, B])。我们需要取得第一个函数并执行它。
  1. var queue = function(funcs) {  
  2.     var f = funcs.shift();  
  3.     f();  
  4. }
复制代码       如果执行这段代码,您将看到一个 TypeError: undefined is not a function。这是因为 A函数没收到回调参数但却试图运行它。让我们换一种调用方法。
  1. var queue = function(funcs) {  
  2.     var next = function() {  
  3.         // ...  
  4.     };  
  5.     var f = funcs.shift();  
  6.     f(next);  
  7. };
复制代码       在 A执行完后会调用 next 方法。将下一步操作放在 next 函数列表中是个很好的做法。我们可以将代码归拢在一起,而且我们能够传递整个数组(即便数组中有很多函数等待执行)。
  1. var queue = function(funcs) {  
  2.     var next = function() {  
  3.         var f = funcs.shift();  
  4.         f(next);  
  5.     };  
  6.     next();  
  7. };
复制代码       到了这一步,我们基本上达到了我们的目标。即函数A 执行后,接着会调用 B,打印出变量的正确值。这里的关键是 shift 方法的使用。它删除数组的第一个元素并返回该元素。一步一步执行下去, funcs数组就会变成 empty(空的)。所以,这可能会导致另一个错误。为了证明这一观点,让我们假设我们仍然需要运行这两个功能,但我们不知道他们的顺序。在这种情况下,两个函数都应该接受回调参数(callback )并执行它。
  1. var A = function(callback) {  
  2.     setTimeout(function() {  
  3.         value = 10;  
  4.         callback();  
  5.     }, 200);  
  6. };  
  7. var B = function(callback) {  
  8.     console.log(value);  
  9.     callback();  
  10. };
复制代码       当然,我们会得到 TypeError: undefined is not a function.

       要阻止这一点,我们应该检查funcs数组是否为空。

  1. var queue = function(funcs) {  
  2.     (function next() {  
  3.         if(funcs.length > 0) {  
  4.             var f = funcs.shift();  
  5.             f(next);  
  6.         }  
  7.     })();  
  8. };
复制代码        我们所做的就是定义 next 函数并调用它。这种写法减少了一点代码。

  让我们试着想象尽可能多的情况。比如当前执行功能的 scope 。函数内的 this 关键字可能指向了全球的 window 对象。,如果我们可以设置自己的scope 当然是件很酷的事情。

  1. var queue = function(funcs, scope) {  
  2.     (function next() {  
  3.           if(funcs.length > 0) {  
  4.               var f = funcs.shift();  
  5.               f.apply(scope, [next]);  
  6.           }  
  7.     })();  
  8. };
复制代码       我们为这个tiny 类库增加了一个参数。接着我们使用 apply  函数,而不是直接调用 f(next),来设置scope 并将参数 next 传递进去。同样的功能,但漂亮多了。

  我们需要的最后一个特性,就是是函数间传递参数的能力。当然我们不知道具体会有多少参数将被使用。这就是为什么我们需要使用 arguments 变量的原因。你可能知道,该变量在每个 JavaScript函数中都是可用的,代表了传进来的参数。它就和一个数组差不多,但不完全是。因为在 apply 方法中我们需要使用真正的数组,使用一个小窍门来进行转换。


  1. var queue = function(funcs, scope) {  
  2.     (function next() {  
  3.           if(funcs.length > 0) {  
  4.               var f = funcs.shift();  
  5.               f.apply(scope, [next].concat(Array.prototype.slice.call(arguments, 0)));  
  6.           }  
  7.     })();  
  8. };
复制代码下面是测试的代码:

  1. // 测试代码  
  2. var obj = {  
  3.     value: null
  4. };  
  5. queue([  
  6.     function(callback) {  
  7.         var self = this;  
  8.         setTimeout(function() {  
  9.             self.value = 10;  
  10.             callback(20);  
  11.         }, 200);  
  12.     },  
  13.     function(callback, add) {  
  14.         console.log(this.value + add);  
  15.         callback();  
  16.     },  
  17.     function() {  
  18.         console.log(obj.value);  
  19.     }  
  20. ], obj);
复制代码 执行后的输出为:
  1. 30
  2. 10
复制代码           为了代码的可读性和美观,我们将部分相关的代码移到一行内:
  1. var queue = function(funcs, scope) {
  2.     (function next() {
  3.           if(funcs.length > 0) {
  4.               funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0)));
  5.           }
  6.     })();
  7. };
复制代码
         你可以 点击这里查看并调试相关代码,完整的测试代码如下:

  1. var queue = function(funcs, scope) {
  2.     (function next() {
  3.           if(funcs.length > 0) {
  4.               funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0)));
  5.           }
  6.     })();
  7. };
  8. var obj = {
  9.     value: null
  10. };
  11. queue([
  12.     function(callback) {
  13.         var self = this;
  14.         setTimeout(function() {
  15.             self.value = 10;
  16.             callback(20);
  17.         }, 200);
  18.     },
  19.     function(callback, add) {
  20.         console.log(this.value + add);
  21.         callback();
  22.     },
  23.     function() {
  24.         console.log(obj.value);
  25.     }
  26. ], obj);
复制代码



 原文出处: krasimirtsonev


【短小强悍的JavaScript异步调用库】相关文章

1. 短小强悍的JavaScript异步调用库

2. JavaScript异步编程助手:Promise模式

3. Blackberry 10展示强悍的HTML5性能

4. JavaScript的4种调用函数的方法

5. Easystar.js:异步的 JavaScript 寻路游戏

6. jQuery AJAX实现调用页面后台方法

7. JScrambler:保护你的JavaScript代码

8. 原生体验挡不住!JavaScript开源跨平台框架NativeScript

9. JavaScript开源跨平台框架NativeScript

10. RapydScript:将特定代码转换成JavaScript的预编译器

本文来源:https://www.51html5.com/a3593.html

点击展开全部

﹝短小强悍的JavaScript异步调用库﹞相关内容

「短小强悍的JavaScript异步调用库」相关专题

其它栏目

也许您还喜欢