`
javayestome
  • 浏览: 1038483 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

javascript 异步编程2

阅读更多

好像有这么一句名言——"每一个优雅的接口,背后都有一个龌龊的实现"。最明显的例子,jQuery。之所以弄得这么复杂,因为它本来就是那复杂。 虽然有些实现相对简明些,那是它们的兼容程度去不了那个地步。当然,世上总有例外,比如mootools,但暴露到我们眼前的接口,又不知到底是那个父类 的东西,结构清晰但不明撩。我之所以说这样的话,因为异步列队真的很复杂,但我会尽可能让API简单易用。无new实例化,不区分实例与类方法,链式,等 时髦的东西都用上。下面先奉上源码:

;( function (){
     var dom = this .dom = this .dom || {
         mix : function (target, source ,override) {
             var i, ride = (override === void 0) || override;
             for (i in source) {
                 if (ride || !(i in target)) {
                     target[i] = source[i];
                 }
             }
             return target;
         }
     }
     //////////////////////////////////////////////////////////////////////
     //=======================异步列队模块===================================
     var Deferred = dom.Deferred = function (fn) {
         return this instanceof Deferred ? this .init(fn) : new Deferred(fn)
     }
     var A_slice = Array.prototype.slice;
     dom.mix(Deferred, {
         get: function (obj){ //确保this为Deferred实例
             return   obj instanceof Deferred ? obj : new Deferred
         },
         ok : function (r) { //传递器
             return r
         },
         ng : function (e) { //传递器
             throw   e
         }
     });
     Deferred.prototype = {
         init: function (fn){ //初始化,建立两个列队
             this ._firing = [];
             this ._fired = [];
             if ( typeof fn === "function" )
                 return this .then(fn)
             return this ;
         },
         _add: function (okng,fn){
             var obj = {
                 ok:Deferred.ok,
                 ng:Deferred.ng,
                 arr:[]
             }
             if ( typeof fn === "function" )
                 obj[okng] = fn;
             this ._firing.push(obj);
             return this ;
         },
         then: function (fn){ //_add的包装方法1,用于添加正向回调
             return   Deferred.get( this )._add( "ok" ,fn)
         },
         once: function (fn){ //_add的包装方法2,用于添加负向回调
             return   Deferred.get( this )._add( "ng" ,fn)
         },
         wait: function (timeout){
             var self = Deferred.get( this );
             self._firing.push(~~timeout)
             return self
         },
         _fire: function (okng,args,result){
             var type = "ok" ,
             obj = this ._firing.shift();
             if (obj){
                 this ._fired.push(obj); //把执行过的回调函数包,从一个列队倒入另一个列队
                 var self = this ;
                 if ( typeof obj === "number" ){ //如果是延时操作
                     var timeoutID = setTimeout( function (){
                         self._fire(okng,self.before(args,result))
                     },obj)
                     this .onabort = function (){
                         clearTimeout(timeoutID );
                     }
                 } else if (obj.arr.length){ //如果是并行操作
                     var i = 0, d;
                     while (d = obj.arr[i++]){
                         d.fire(args)
                     }
                 } else { //如果是串行操作
                     try { //
                         result = obj[okng].apply( this ,args);
                     } catch (e){
                         type = "ng" ;
                         result = e;
                     }
                     this ._fire(type, this .before(args,result))
                 }
             } else { //队列执行完毕,还原
                 ( this .after || Deferred.ok)(result);
                 this ._firing = this ._fired;
                 this ._fired = [];
             }
             return this ;
         },
         fire: function (){ //执行正向列队
             return this ._fire( "ok" , this .before(arguments));
         },
         error: function (){ //执行负向列队
             return this ._fire( "ng" , this .before(arguments));
         },
 
         abort: function (){ //中止列队
             ( this .onabort || Deferred.ok)();
             return this ;
         },
         //每次执行用户回调函数前都执行此函数,返回一个数组
         before: function (args,result){
            return result ? result instanceof Array ? result : [result] : A_slice.call(args)
         },
         //并行操作,并把所有的子线程的结果作为主线程的下一个操作的参数
         paiallel : function (fns) {
             var self = Deferred.get( this ),
             obj = {
                 ok:Deferred.ok,
                 ng:Deferred.ng,
                 arr:[]
             },
             count = 0,
             values = {}
             for ( var key in fns){ //参数可以是一个对象或数组
                 if (fns.hasOwnProperty(key)){
                     ( function (key,fn){
                         if ( typeof fn == "function" )
                             fn = Deferred(fn);
                         fn.then( function (value){
                             values[key] = value;
                             if (--count <= 0){
                                 if (fns instanceof Array){ //如果是数组强制转换为数组
                                     values.length = fns.length;
                                     values = A_slice.call(values)
                                 }
                                 self._fire( "ok" ,[values])
                             }
                         }).once( function (e){
                             self._fire( "ng" ,[e])
                         });
                         obj.arr.push(fn);
                         count++
                     })(key,fns[key])
                 }
             }
             self.onabort = function (){
                 var i = 0, d;
                 while (d = obj.arr[i++]){
                     d.abort();
                 }
             }
             self._firing.push(obj);
             return self
         },
         //处理相近的迭代操作
         loop : function (obj, fn, result) {
             obj = {
                 begin : obj.begin || 0,
                 end   : ( typeof obj.end == "number" ) ? obj.end : obj - 1,
                 step  : obj.step  || 1,
                 last  : false ,
                 prev  : null
             }
             var step = obj.step,
             _loop = function (i,obj){
                 if (i <= obj.end) {
                     if ((i + step) > obj.end) {
                         obj.last = true ;
                         obj.step = obj.end - i + 1;
                     }
                     obj.prev = result;
                     result = fn.call(obj,i);
                     Deferred.get(result).then(_loop).fire(i+step,obj);
                 } else {
                     return result;
                 }
             }
             return (obj.begin <= obj.end) ? Deferred.get( this ).then(_loop).fire(obj.begin,obj) : null ;
         }
     }
     //将原型方法转换为类方法
     "loop wait then once paiallel" .replace(/\w+/g, function (method){
         Deferred[method] = Deferred.prototype[method]
     });
})();

Deferred提供的接口其实不算多,then once loop wait paialle就这五个,我们可以new一个实例出来,用它的实例方法,可以直接用类名加方法名,其实里面还是new了一个实例。另外,还有两个专门用于 复写的方法,before与after。before执行于每个回调函数之前,after执行于所有回调之后,相当于complete了。既然是列队,就 有入队操作与出队操作,我不可能使用queue与dequeue这样土的命名。queue换成两个时间状语,then与once,相当于jQuery的 done、fail,或dojo的addCallback、addErrback。dequeue则用fire与error取替,jQuery1.5的 beta版也曾经用过fire,不知为何换成resolve这样难记的单词。好了,我们先不管其他API,现在就试试身手吧。

       var log = function (s) {
         window.console && window.console.log(s);
       }
       dom.Deferred( function () {
         log(1); //1
       })
       .then( function () {
         log(2); //2
       })
       .then( function () {
         log(3); //3
       })
       .fire();
//如果不使用异步列队,实现这种效果,就需要用套嵌函数
/*
       var fun = function(fn){
         fn()
       };
       fun(function(){
         log(1);
         fun(function(){
           log(2);
           fun(function(){
             log(3);
           })
         });
       });
*/

当然,现在是同步操作。注意,第一个回调函数是作为构造器的参数传入,可以节约了一个then^_^。

默认如果回调函数存在返回值,它会把它作为下一个回调函数的参数传入,如:

dom.Deferred( function (a) {
   a +=  10
   log(a); //11
   return a
})
.then( function (b) {
   b += 12
   log(b); //23
   return b
})
.then( function (c) {
   c += 130
   log(c); //153
})
.fire(1);

我们可以重载before函数,让它的结果不影响下一个回调函数。在多投事件中,我们也可以在before中定义,如果返回false,就中断队列了。

我们再来看它如何处理异常。dom.Deferred的负向列队与jQuery的是完全不同的,jQuery的只是正向列队的一个克隆,而在dom.Deferred中,负向列队只是用于突发情况,是配角。

dom.Deferred( function () {
   log(1111111111) //11111111111
}).
   then( function () {
   throw "error!" ; //发生错误
}).
   then( function (e) { //这个回调函数不执行
   log(e+ "222222" )
   return 2222222
}).
   once( function (e){ //直到 遇上我们自定义的负向回调
   log(e+ '333333' ) //error!333333
<td cl
1
2
分享到:
评论

相关推荐

    Javascript异步编程(英文版)

    《JavaScript异步编程》这本书深入探讨了现代JavaScript开发中的关键主题——如何在不陷入混乱的情况下处理并发和并发任务。本书作者Trevor Burnham通过精确平衡的浏览器端和服务器端示例,为读者提供了一份简洁的...

    JavaScript异步编程g.pdf

    JavaScript异步编程是前端开发领域中的一个重要概念,它允许程序在等待长时间操作(如网络请求)时继续执行其他任务,而不是简单地暂停或停止,从而提升用户体验。本书《JavaScript异步编程》作为图灵程序设计丛书的...

    Javscript高性能编程+Javascript异步编程

    "JavaScript高性能编程"和"JavaScript异步编程"是两个关键的JavaScript专题,对于提升应用程序的性能和用户体验至关重要。 一、JavaScript高性能编程 1. **优化代码执行效率**:了解JavaScript引擎的工作原理,如...

    javascript异步编程 设计快速响应的网络应用 源码

    JavaScript异步编程是Web开发中的核心技能,它使得开发者能够设计出快速响应的网络应用,提供流畅的用户体验。这本书的源码提供了深入理解和实践这些概念的机会。以下是对这个主题的详细探讨。 首先,我们要理解...

    《JavaScript异步编程》PDF版本下载.txt

    ### JavaScript异步编程知识点概述 #### 一、异步编程概念 在JavaScript中,异步编程是一种处理长时间运行操作而不阻塞主线程的方法。这种方式允许程序在等待某些操作(如I/O操作、网络请求等)完成的同时,继续...

    Javascript异步编程的4种方法

    ### JavaScript异步编程的四种方法 #### 概述 JavaScript是一种广泛使用的脚本语言,尤其在Web开发领域占据着核心地位。由于浏览器环境的限制,JavaScript最初被设计为单线程执行模型。这意味着在同一时间只能执行...

    再谈JavaScript异步编程

    在早期的JavaScript异步编程中,回调函数是处理异步操作的主要方式。然而,嵌套回调函数(俗称回调地狱)会导致代码难以阅读和维护。例如: ```javascript makeAjaxCall('***', (result) =&gt; { result = JSON.parse...

    JavaScript设计模式+JavaScript模式+JavaScript异步编程

    3. **JavaScript异步编程**: 异步编程是JavaScript的重要特性,用于处理耗时操作,如网络请求和文件读写,以避免阻塞主线程。主要方法有: - 回调函数:最基础的异步处理方式,但可能导致回调地狱问题。 - 事件...

    JavaScript异步编程学习

    JavaScript异步编程是Web开发中的核心概念,尤其在构建交互性强、响应迅速的网页应用时不可或缺。这篇博客“JavaScript异步编程学习”可能探讨了如何有效地处理非阻塞操作,以避免程序因等待I/O或其他耗时任务而陷入...

    JavaScript异步编程

    JavaScript异步编程是前端开发中的重要概念,它允许在执行长时间运行的任务时不会阻塞主线程,从而提升用户体验。异步编程的核心在于,它不会立即得到结果,而是在某个未来的时刻,当任务执行完毕后,才会得到通知。...

    藏经阁-JavaScript异步编程.pdf

    藏经阁-JavaScript异步编程 JavaScript异步编程是JavaScript语言的一大特点,它可以使得JavaScript语言在单线程的情况下,执行多个任务,而不需要阻塞其他任务。异步编程的解决方案有多种,包括回调函数、Promise、...

    JavaScript 异步编程:基本指南.docx

    本文将深入讲解JavaScript异步编程的基础和高级概念,帮助开发者理解并掌握这一核心技能。 1. **异步编程的基本概念** 在JavaScript中,异步编程意味着某些操作不会阻塞程序的执行,而是以非阻塞的方式进行。这是...

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

    本文主要介绍了JavaScript异步编程设计的相关内容,为了构建快速响应的网络应用,文章深入探讨了异步编程的多种方法,并提供了实用的实践案例。异步编程是Web开发中的一个重要概念,它允许程序在等待耗时操作(如I/O...

    JavaScript 异步编程

    JavaScript 异步编程

    基于Javascript的异步编程分析.pdf

    2. 提高性能:异步编程可以使得JavaScript可以更好地利用系统资源,从而提高性能。 异步编程的缺点 异步编程也有一些缺点: 1. 代码难以维护:异步编程的代码难以维护和 debug。 2. 回调地狱:异步编程中,回调...

    详解JavaScript异步编程中jQuery的promise对象的作用_.docx

    详解JavaScript异步编程中jQuery的promise对象的作用 Promise 对象是 JavaScript 异步编程中的一种重要概念,特别是在 jQuery 库中。Promise 对象的主要作用是解决异步编程中的回调地狱问题,提供了一种简洁的方式...

    前端开发、JavaScript、asyncawait、异步编程、异常处理,学习JavaScript异步编程

    JavaScript中的异步编程是Web前端开发的核心技能,而async/await是现代JavaScript处理异步操作的一种优雅方式。这个模式使得代码更加清晰、易于理解和维护,尤其对于初学者来说,掌握async/await能大大提高开发效率...

Global site tag (gtag.js) - Google Analytics