二分之一

Just Jason's Blog

Javascript异步编程几种方式及Ajax串行执行探讨

由于JS是单线程语言,程序在同步执行时,如果耗时较长就会阻塞下面的进程,而异步编程则可以避免这个问题。异步编程在耗时长的操作中非常重要,比如连接网络文件,读取本地文件等。

Ajax就是经典的异步程序,但是多个ajax需要串行执行时,怎样才能优雅有序的执行呢?本文将探讨大规模异步ajax串行执行时的编程问题。

常用的几种异步编程方式有:【本文代码范例基于jquery】

一、回调函数

function a(callback){
    $.get("a.php",function(data){
        callback(data);
    });
}
function b(data){
    console.log(data);
}
a(b);

a执行完后,b再执行。这是典型的回调函数用法,但是回调函数代码高度耦合,代码可读性不高,而且比较混乱,如果回调流程比较长,需要从中减掉一个回调流程时,不易修改。

二、自定义事件监听

$(a).bind('done',function(evt,data){  //监听事件
    b(evt,data);
});
function a(callback){
    $.get("a.php",function(data){
        jQuery.event.trigger('done',data); //触发事件
    });
}
function b(evt,data){
    console.log(data);
}

自定义事件相对于回调函数,耦合底降低,但是程序运行流程不清晰。

三、”观察者模式”(observer pattern)。又称“发布/订阅模式”

其实这种模式和自定义事件有异曲同工之妙,看起来基本类似,但是“发布/订阅模式”能更好的管理当前的消息有多少订阅者,并能轻松取消事件。

本模式使用jquery.ba-tinypubsub.js [github]

以下是jquery.ba-tinypubsub.js的源码。

//jquery.ba-tinypubsub.js,基于jquery1.7以上版本
(function($) {

var o = $({});

$.subscribe = function() {
o.on.apply(o, arguments);
};

$.unsubscribe = function() {
o.off.apply(o, arguments);
};

$.publish = function() {
o.trigger.apply(o, arguments);
};

}(jQuery));

使用方法:

$.subscribe("done", b); //订阅事件(监听)
function a(callback){
    $.get("a.php",function(data){
        $.publish('done',data); //发布事件
    });
}
function b(evt,data){
    console.log(data);
}
a();
//$.unsubscribe("done",b); //取消订阅

四、promises模式/jquery deferred对象

Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。

简单来说,就是每次返回一个promises对象,这个对象可以添加then或fail等方法,以实现回调方法的调用。

jquery中用deferred来实现promises的。jquery deferred对象介绍,请移步《jQuery deferred对象API详解及DEMO》

五、串行ajax有序执行探讨

a.php

//a.php
<?php
die('b');
?>

b.php,b.php必须接受一个code参数,值必须为a.php返回的。

//b.php
<?php
$code = $_GET['code'];
if(isset($code) && $code=="b"){
    die("c");
}
?>

现在需要实现从ajax从a.php拿到a的值,再将a的值用ajax请求b.php,最终拿到b的值。 这是一个常会碰到的ajax串行有序执行的例子,解决方案大概有:

1、回调函数
2、自定义事件监听或“订阅发布模式”
3、ajax队列,用一个数组来做先进先出的队列,有序的管理回调函数的执行顺序。
4、 jquery deferred对象实现
从1.7开始,ajax不再返回xhr对象,而是返回deferred对象。

笔者根据jquery ajax的新特性,通过函数递归的特性,简单的写了一个串行ajax执行的方法,可以实现大规模ajax顺序执行,仅仅是抛砖引玉,欢迎大家完善。

function a(){
   return $.get("a.php");
}
function b(code){
   return $.get("b.php?code="+code);
}
var async = {
    pos:0,
    end:function(){},
    req:function(arr,data){
        var that = this;
        arr[that.pos](data).done(function(_data){
            if(that.pos+1<arr.length){ //还有下一个
                that.pos++;
                that.req(arr,_data);
            }else{
                that.pos=0;
                that.end(_data);
            }
        });
    }
}
var arrayOfAjax = [a, b];
async.end = function(data){  //队列执行完毕
    alert(data);
}
async.req(arrayOfAjax);//开始执行

最后修改时间:2014年9月10日星期三晚上7点51