如果在一个函数中,我们需要的数据是要从ajax获取。如果用ajax同步 的方法,浏览器会挂起,这是一个很讨厌的事情。
而ajax异步 在浏览器中的实现是立即返回的,而我们要的数据还没有被获取。
那用ajax异步 的方法怎么做才能达到我们的目的呢?让我们一步步实现伪同步.
先给个简单的方法:
function foo(data){ if(undefined==data) return ajaxQueue({...},{callback:arguments.callee}); ......someting...... }
也就是说:
函数foo内部有ajax异步(ajaxQueue就是入口)的请求,而且ajax后的结果对foo的内部(someting)执行有影响,因此需要在foo内部进行判断是否ajax异步请求已经完成 ,或者说调用者是否是ajax异步请求 .
上面代码中用了一个简单的判断
if(undefined==data)
而
{callback:arguments.callee}
就是告诉ajaxQueue取到数据后,再回调foo了.
不过这个方法有问题,也就是借用了foo 函数的参数值,在某些场合也许就不适用了。因此这个方法是有问题的,ajaxQueue的实现也就失去了讨论的意义。
首先让我们完善上面的方法:注意闭包的用法(也不知道会不会造成内存泄漏)
function ajaxCallback(queue,args){ var func=arguments.callee.caller; var length=queue.length; for (var i=0;i<queue.length;i++) (function(){ var o=queue[i]; var _old = o.complete; o.complete = function(){ if ( _old ) _old.apply( this, arguments ); length--; if (0==length) { func.apply(ajaxCallback,args); } }; jQuery.ajax(o); })(); }
调用:
function foo(ddd){ if(this!==ajaxCallback){ return ajaxCallback([ {url:'/1.txt',complete:function(){alert(1);}}, {url:'/1.txt',complete:function(){alert(2);}}], arguments); } alert(arguments.length); alert(ddd) } foo(3);
这里面还有一个问题,就是虽然没有借用参数,但是借用了this(我是不是绕的弯弯太多了,直奔正解不就行了,其实这是我解决这个时候的思路,自己记录一下).对OO的编程可就有产生了新的麻烦。
改一下:
function ajaxCallback(queue,args){ var func=arguments.callee.caller; var length=queue.length; for (var i=0;i<queue.length;i++){ (function (){ var o=queue[i]; var _old = o.complete; o.complete = function(){ if ( _old ) _old.apply( this, arguments); length--; if (0==length) { Callback(func,args[0],args[1]); } }; jQuery.ajax(o); })(); } } function Callback(func,self,args){ func.apply(self,args); }
测试:
function foo(ddd){ if(arguments.callee.caller!=Callback){ return ajaxCallback([ {url:'/1.txt',complete:function(){alert(1);}}, {url:'/1.txt',complete:function(){alert(2);}}], [this,arguments]); } alert(ddd); alert(this); } foo(3); var f={}; f.foo=foo; f.foo(3);
这回好了。不占参数,this也得到了正确(其实是调用的时候主动传过去的)传递.
ajax 伪同步实现.
备注 :您需要明白的是,我这里说的同步指的是调用ajax的函数实现了伪阻塞,关于多ajax请求伪同步的方法有队列法,比如jQuery的插件ajaxQueue ,从某种意义上说我的这个方法也可以实现,不过既然人家工作的很好,就不费这个力气了.
暂时思路只能到这里,进一步要靠实践了.
更新.感觉函数的名字起的不好,改了下,而且增加了不需要回调的判断:
//多ajax请求队列,支持完结回调 function ajaxQueue(queue,thiss,argss,other){ if (arguments.length<1) return false; if (!argss) argss=[]; var args=[]; for (var i=0;i<argss.length ;i++ ) args.push(argss[i]); if (other) for (var i=0;i<other.length ;i++) args.push(other[i]); var func=arguments.callee.caller; (function (a,func,thiss,args){ var o=a.shift(); //增加了判断是否要回调 if (!o) return thiss?thisCallback(func,thiss,args):false; var self=arguments.callee; var _old = o.complete; o.complete = function(){ if ( _old ) _old.apply( this, arguments); self(a,func,thiss,args); }; jQuery.ajax(o); })(queue,func,thiss,args); return false; } //回调函数,保持原来的this指针 function thisCallback(func,thiss,args){ if (func.constructor == Function) func.apply(thiss,args); return false; }