论坛首页 AJAX版 AJAX

[原创]伪同步调用ajax(伪阻塞)

浏览 737 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2008-07-03 关键字: ajax 阻塞

如果在一个函数中,我们需要的数据是要从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;
}
 
   
最后更新时间:2008-07-02
终于想明白自己要说什么了,也找到了合适的词汇,并重新编辑了帖子。
   
0 请登录后投票
最后更新时间:2008-07-03

根据前面的思考重新写了一个伪同步回调模式的ajax队列函数:可以完全替代jQuery插件ajaxQueue了,而且功能更强.

//回调函数,保持原来的this指针
function thisCallback(func,thiss,args){
	func.apply(thiss,args);
	return false;
}
//把arguments分成argss,other两部分完全是为了调用方便.方便到哪里了你用了就明白了.
function ajaxQueue(queue,thiss,argss,other){
	if (arguments.length<3) return false;
	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 thisCallback(func,thiss,args);
		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;
}

 调用的例子:动态执行服务器端的js

//参数a是要动态请求的服务器端的js文件
function test(a){
	if(arguments.callee.caller==thisCallback){
		alert('ok');
		return;
       }
	var queue=[];
	for(var i=0;i<a.jslist.length;i++){
		queue.push({url:a.jslist[i],success:function(js){
			try{
				window.eval(js);
			}catch(ex){//错误处理代码,这个要看你的处理了
				$('#error').append('<pre>Error:\n'+ex.message + '\n'+ (ex.lineNumber || ex.number)+'</pre>');
			}
		}});
	}
	ajaxQueue(queue,this,['ajaxQueue']);
	return;
}

 当然还可以设计出success出错后的中断队列的模式,暂时不写了,因为很容易,等我的应用有需求的时候再写吧.

   
0 请登录后投票
最后更新时间:2008-07-15
好象并不能解决我的问题,因为我的问题本身是有问题的,无法解决,你的想法很好,应该对于其他问题很有用
   
0 请登录后投票
最后更新时间:2008-07-15
gui1401 写道
好象并不能解决我的问题,因为我的问题本身是有问题的,无法解决,你的想法很好,应该对于其他问题很有用

我正在写的nicEdit 打包器
用的就是这个方法+jCT做的,现在还没有做完,感兴趣可以看看,有实例参考也许会对你有启发.
源文件目录
http://ne.16lo.com/src/nicEditor/
achun.html就是jCT模板,
src/nicEditor/src 目录是nicEditor的源文件
_.php是入口文件,不允许浏览器访问,内容如下:
foreach ($AQ as $Q=>$P){
	switch ($Q){
		case 'entry':
			se_Msg(se_webPath(dirname(__FILE__)));
			break;
	}
}

其实就是输出一个相对浏览器的entry URL,就是他了
{"entry":"/src/nicEditor"}

我的服务器目录是配置了只有src下的才能浏览,
使用FF+FireBug可以监视到整个实现.
   
0 请登录后投票
论坛首页 AJAX版 AJAX

跳转论坛:
JavaEye推荐