短小强悍的JavaScript异步调用库

对于博文 20行完成一个JavaScript模板引擎 的备受好评我感到很惊讶,并决定用此文章介绍使用我经常使用的另一个小巧实用的工具.我们知道,在浏览器中的 JavaScript 绝大部分的操作都是异步的(asynchronous),所以我们一直都需要使用回调方法,而有时不免陷入回调的泥淖而欲死欲仙。

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


1

2

3

4

5

6

7

8

9

var value; 

var A = function() { 

    setTimeout(function() { 

        value = 10; 

    }, 200); 

var B = function() { 

    console.log(value); 

}

  那么,现在如果我们运行 A();B(); 我们将在控制台看到输出为 undefined . 之所以会这样是因为 A 函数使用了异步方式设置 value 。我们能做的就是传一个回调函数给A,并让函数A在执行完后执行回调函数。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

var value; 

var A = function(callback) { 

  setTimeout(function() { 

    value = 10; 

    callback(); 

  }, 200); 

}; 

var B = function() { 

  console.log(value); 

}; 

A(function() { 

  B(); 

});

  这样确实有用,但想象一下加入我们需要运行5个或更多方法时将会发生什么。一直传递回调函数将会导致混乱和非常不雅观的代码。
好的解决办法是写一个工具函数,接受我们的程序并控制整个过程。让我们先从最简单的开始:


1

2

3

var queue = function(funcs) { 

    // 接下来请看,董卿??? 

}

  接着,我们要做的是通过传递A和B来运行该函数 - queue([A, B])。我们需要取得第一个函数并执行它。


1

2

3

4

var queue = function(funcs) { 

    var f = funcs.shift(); 

    f(); 

}

  如果执行这段代码,您将看到一个 TypeError: undefined is not a function。这是因为 A函数没收到回调参数但却试图运行它。让我们换一种调用方法。


1

2

3

4

5

6

7

var queue = function(funcs) { 

    var next = function() { 

        // ... 

    }; 

    var f = funcs.shift(); 

    f(next); 

};

  在 A执行完后会调用 next 方法。将下一步操作放在 next 函数列表中是个很好的做法。我们可以将代码归拢在一起,而且我们能够传递整个数组(即便数组中有很多函数等待执行)。


1

2

3

4

5

6

7

var queue = function(funcs) { 

    var next = function() { 

        var f = funcs.shift(); 

        f(next); 

    }; 

    next(); 

};

  到了这一步,我们基本上达到了我们的目标。即函数A 执行后,接着会调用 B,打印出变量的正确值。这里的关键是 shift 方法的使用。它删除数组的第一个元素并返回该元素。一步一步执行下去, funcs数组就会变成 empty(空的)。所以,这可能会导致另一个错误。为了证明这一观点,让我们假设我们仍然需要运行这两个功能,但我们不知道他们的顺序。在这种情况下,两个函数都应该接受回调参数(callback )并执行它。


1

2

3

4

5

6

7

8

9

10

var A = function(callback) { 

    setTimeout(function() { 

        value = 10; 

        callback(); 

    }, 200); 

}; 

var B = function(callback) { 

    console.log(value); 

    callback(); 

};

  当然,我们会得到 TypeError: undefined is not a function.
要阻止这一点,我们应该检查funcs数组是否为空。


1

2

3

4

5

6

7

8

var queue = function(funcs) { 

    (function next() { 

        if(funcs.length > 0) { 

            var f = funcs.shift(); 

            f(next); 

        

    })(); 

};

  我们所做的就是定义 next 函数并调用它。这种写法减少了一点代码。

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


1

2

3

4

5

6

7

8

var queue = function(funcs, scope) { 

    (function next() { 

          if(funcs.length > 0) { 

              var f = funcs.shift(); 

              f.apply(scope, [next]); 

          

    })(); 

};

  我们为这个tiny 类库增加了一个参数。接着我们使用 apply  函数,而不是直接调用 f(next),来设置scope 并将参数 next 传递进去。同样的功能,但漂亮多了。

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


1

2

3

4

5

6

7

8

var queue = function(funcs, scope) { 

    (function next() { 

          if(funcs.length > 0) { 

              var f = funcs.shift(); 

              f.apply(scope, [next].concat(Array.prototype.slice.call(arguments, 0))); 

          

    })(); 

};

  下面是测试的代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// 测试代码 

var obj = { 

    value: null

}; 

queue([ 

    function(callback) { 

        var self = this

        setTimeout(function() { 

            self.value = 10; 

            callback(20); 

        }, 200); 

    }, 

    function(callback, add) { 

        console.log(this.value + add); 

        callback(); 

    }, 

    function() { 

        console.log(obj.value); 

    

], obj);

  执行后的输出为:


1

2

30 

10

  为了代码的可读性和美观,我们将部分相关的代码移到一行内:


1

2

3

4

5

6

7

var queue = function(funcs, scope) { 

    (function next() { 

          if(funcs.length > 0) { 

              funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0))); 

          

    })(); 

};

  你可以 点击这里查看并调试相关代码,完整的测试代码如下:


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

var queue = function(funcs, scope) { 

    (function next() { 

          if(funcs.length > 0) { 

              funcs.shift().apply(scope || {}, [next].concat(Array.prototype.slice.call(arguments, 0))); 

          

    })(); 

}; 

var obj = { 

    value: null

}; 

queue([ 

    function(callback) { 

        var self = this

        setTimeout(function() { 

            self.value = 10; 

            callback(20); 

        }, 200); 

    }, 

    function(callback, add) { 

        console.log(this.value + add); 

        callback(); 

    }, 

    function() { 

        console.log(obj.value); 

    

], obj);

时间: 2024-08-27 07:29:04

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

用Html5/CSS3做Winform,一步一步教你搭建CefSharp开发环境(附JavaScript异步调用C#例子,及全部源代码)上

本文为鸡毛巾原创,原文地址:http://www.cnblogs.com/jimaojin/p/7077131.html,转载请注明 CefSharp说白了就是Chromium浏览器的嵌入式核心,我们用此开发Winform程序也就相当于在程序里面内嵌了一个谷歌浏览器.所以H5/CSS3以及各种Web开发界面设计的优势就可以完全发挥出来. 由于CefSharp更新及时,所以使用此浏览器控件可能是对于Html5/CSS3支持最优秀的方案了. 1.首先我用的是VS2015,这里新建一个空白解决方案.

从小小题目逐步走进 JavaScript 异步调用

问题 原题来自 @若泽[wangwenlin] 的提问. 可修改下面的 aa() 函数,目的是在一秒后用 console.log() 输出 want-value function aa() { setTimeout(function() { return "want-value"; }, 1000); } 但是,有额外要求: aa() 函数可以随意修改,但是不能有 console.log() 执行 console.log() 语句里不能有 setTimeout 包裹 解答 也许这是个面

JavaScript异步交互

JavaScript 异步编程简介 回调函数和异步执行 所谓的异步指的是函数的调用并不直接返回执行的结果,而往往是通过回调函数异步的执行. 我们先看看回调函数是什么: var fn = function(callback) { // do something here ... callback.apply(this, para); }: var mycallback = function(parameter) { // do someting in customer callback }: //

探索Javascript异步编程

异步编程带来的问题在客户端Javascript中并不明显,但随着服务器端Javascript越来越广的被使用,大量的异步IO操作使得该问题变得明显.许多不同的方法都可以解决这个问题,本文讨论了一些方法,但并不深入.大家需要根据自己的情况选择一个适于自己的方法. 笔者在之前的一片博客中简单的讨论了Python和Javascript的异同,其实作为一种编程语言Javascript的异步编程是一个非常值得讨论的有趣话题. JavaScript 异步编程简介 回调函数和异步执行 所谓的异步指的是函数的调

Effective JavaScript Item 62 在异步调用中使用嵌套或者命名的回调函数

在一开始,理解异步程序的调用顺序会有些困难.比如,下面的程序中,starting会先被打印出来,然后才是finished: downloadAsync("file.txt", function(file) { console.log("finished"); }); console.log("starting"); downloadAsync方法在执行之后会立即返回,它只是为下载这个行为注册了一个回调函数而已. 由于JavaScript"

强悍的Javascript图表库:Highcharts

如果你正在寻找如何创建图表,那我们这篇文章就是为你准备的.我曾经在网上找了很多的资料,怎样去完美的解决创建图表的方案,让我惊喜的是发现了一个很好的很强悍的Javascript图表库:Highcharts.这是一个纯Javascript库,它主要包括两个部分:Highcharts和Highstock.Highcharts可以为您的网站或Web应用程序提供直观,互动式的图表.目前支持线,样条,面积,areaspline,柱形图,条形图,饼图和散点图类型.Highstock可以为您方便地建立股票或一般

【javascript 进阶】异步调用

前言 javascript的中的异步是很重要的概念,特别是ajax的提出,给整个web带来了很大的影响,今天就介绍下javascript的异步编程. 同步与异步 何为同步?何为异步呢? 同步:说白了就是程序一步一步从下向下执行,没有什么别的代码的跳动,就是按序执行,和在景区里女生上厕所是排队是一样的(每次女厕都是有好多人在排队).可以看成是一个单线程问题. 异步:异步就是程序可以跳着执行,开始执行一段程序之后不用等返回结果就执行其他的代码,等结果返回之后在对结果进行处理,也就是可以在有限的时间内

JavaScript异步编程设计快速响应的网络应用

JavaScript已然成为了多媒体.多任务.多内核网络世界中的一种单线程语言.其利用事件模型处理异步触发任务的行为成就了JavaScript作为开发语言的利器.如何深入理解和掌握JavaScript异步编程变得尤为重要!!!<JavaScript异步编程设计快速响应的网络应用>提供了一些方法和灵感. 一.深入理解JavaScript事件 1. 事件的调度 JavaScript事件处理器在线程空闲之前不会运行(空闲时运行). var start = new Date(); setTimeout

JavaScript异步编程(2)- 先驱者:jsDeferred

原文出处: linkFly   欢迎分享原创到伯乐头条 JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascript的异步编程,jsDeferred也是有必要探索的:因为Promise/A+规范的制定基本上是奠定在jsDeferred上,它是javascript异步编程中里程碑式的作品.jsDeferred自身的实现也是非常有意思的. 本文将探讨项目js