`
achun
  • 浏览: 311719 次
  • 性别: Icon_minigender_1
  • 来自: 河南郑州
社区版块
存档分类
最新评论

[原创]伪同步调用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;
}
分享到:
评论
7 楼 zlt2000 2009-05-08  
谢谢你的详细答复
6 楼 achun 2009-05-08  
<div class="quote_title">zlt2000 写道</div>
<div class="quote_div">看不懂怎样使用,能否给一些使用的演示代码</div>
<p> </p>
<p>晕呀,那个打包工具的代码没有了,链接当然也无效了。</p>
<p>其实这就是一个ajax获取数据的工具,我的应用中需要多次向后台进行ajax请求,而这些请求必须是按次序进行的。</p>
<p>举一个实际的例子吧</p>
<p>您如果看了我的博客的话,会发现<a href="http://achun.iteye.com/category/33268" target="_blank">jCT</a> 这个前台模板工具。对于模板来说有两部分</p>
<p>1.是模板文件</p>
<p>2.对应的数据</p>
<p>对于前台模板工具来说,这两部分要分别从后台获取的,如果采用ajax方法取这两个数据的时候,可以发出两个ajax请求,但是在任何一个请求完成以后就要判断另一个是否也完成了,这有些麻烦。</p>
<p>如果采用我上面说的为阻塞,也就是ajax队列的方法就不存在这个问题,因为事实上每次只有一个ajax的请求被发出,队列中的请求是顺序执行的。</p>
<p> </p>
<p>比如有一个列表的模板文件 /template/list.html</p>
<p>而对应的后台数据请求是   /?getlist=99</p>
<p>处理这两个数据的对象是   </p>
<pre name="code" class="js">obj={
  template:function(){},
  listdata:function(){}
}</pre>
 
<p>那调用代码可以是这样</p>
<pre name="code" class="js">ajaxQueue('/template/list.html',obj,obj.template);
ajaxQueue('/?getlist=99',obj,obj,listdata);</pre>
<p>很明显当第2个请求完成的时候,模板已经正确处理过了,可以进行视图的表现了。</p>
<p>事实上我上面的例子根本就无法在我上面提供的函数中正确运行,不好意思,那是最初的想法和代码,现在的写法如下</p>
<pre name="code" class="js">function ajaxQueue(data,apply,cb,args,ask){
       if(typeof apply=='string' &amp;&amp; !confirm(apply)) return;
if(typeof cb=='string' &amp;&amp; !confirm(cb)) return;
if(typeof args=='string' &amp;&amp; !confirm(args)) return;
if(typeof ask=='string' &amp;&amp; !confirm(ask)) return;//上面这些个判断都是用在缺少足够的参数,并且有提交提问的判断
if(typeof apply=='string') apply=false;
var url,dat,type,datatype;
if(typeof data=='string'){
url=data;
dat=null;
type='GET';
datatype='text';
}else{
url='/';
dat=$.toJSON(data);
type='POST';
datatype='json';
}
if (arguments.length)
ajaxQueue.Queue.push({
url:url,
data:dat,
userData:{
cb:apply===false?null:(typeof cb=='function'?cb:arguments.callee.caller),
apply:apply ||window,
args:(args instanceof Array)?args:(cb instanceof Array?cb:[])
},
type:type,
dataType:datatype,
error:function(xhr){
if(xhr.responseText=='')
alert('无效的请求.');
else
alert('服务器数据错误.')
setTimeout('ajaxQueue()',0);
},
success: function(json){
thisCallback(this.userData.cb,this.userData.apply,[json].concat(this.userData.args));
setTimeout('ajaxQueue()',0);
}
});
var o=ajaxQueue.Queue.shift();
if(o) jQuery.ajax(o);
}
ajaxQueue.Queue=[];

function thisCallback(func,apply,args){
if (typeof func=='function'){
if (!(args instanceof Array)) args=args==undefined?[]:[args];
func.apply(apply,args);
}
return false;
}</pre>
<p> </p>
<p>在上述写法中,ajax请求的数据data被自动的识别了。至于dat=$.toJSON(data) 的用法,参见我的另外一篇文章</p>
<h3 class="type_original" title="原创"><a href="http://achun.iteye.com/blog/200417">降低前后台业务逻辑上的耦合度,前后台细粒度数据通讯的方法</a></h3>
<p> </p>
<p> </p>
5 楼 zlt2000 2009-05-08  
看不懂怎样使用,能否给一些使用的演示代码
4 楼 achun 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可以监视到整个实现.
3 楼 gui1401 2008-07-15  
好象并不能解决我的问题,因为我的问题本身是有问题的,无法解决,你的想法很好,应该对于其他问题很有用
2 楼 achun 2008-07-03  
<p>根据前面的思考重新写了一个伪同步回调模式的ajax队列函数:可以完全替代jQuery插件ajaxQueue了,而且功能更强.</p>
<pre name='code' class='js'>//回调函数,保持原来的this指针
function thisCallback(func,thiss,args){
func.apply(thiss,args);
return false;
}
//把arguments分成argss,other两部分完全是为了调用方便.方便到哪里了你用了就明白了.
function ajaxQueue(queue,thiss,argss,other){
if (arguments.length&lt;3) return false;
var args=[];
for (var i=0;i&lt;argss.length ;i++ )
args.push(argss[i]);
if (other)
for (var i=0;i&lt;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;
}</pre>
<p> 调用的例子:动态执行服务器端的js</p>
<pre name='code' class='js'>//参数a是要动态请求的服务器端的js文件
function test(a){
if(arguments.callee.caller==thisCallback){
alert('ok');
return;
       }
var queue=[];
for(var i=0;i&lt;a.jslist.length;i++){
queue.push({url:a.jslist[i],success:function(js){
try{
window.eval(js);
}catch(ex){//错误处理代码,这个要看你的处理了
$('#error').append('&lt;pre&gt;Error:\n'+ex.message + '\n'+ (ex.lineNumber || ex.number)+'&lt;/pre&gt;');
}
}});
}
ajaxQueue(queue,this,['ajaxQueue']);
return;
}</pre>
<p> 当然还可以设计出success出错后的中断队列的模式,暂时不写了,因为很容易,等我的应用有需求的时候再写吧.</p>
1 楼 achun 2008-07-02  
终于想明白自己要说什么了,也找到了合适的词汇,并重新编辑了帖子。

相关推荐

    伪同步调用ajax(伪阻塞)

    伪同步调用ajax(伪阻塞); 伪同步调用ajax(伪阻塞);

    AJAX同步或异步流程图

    1. **同步通信**:在同步模式下,浏览器会阻塞其他所有脚本执行,直到当前的AJAX请求完成。这意味着用户无法进行任何其他操作,直到请求返回结果。这种方式虽然简单,但会导致页面无响应,影响用户体验。 2. **异步...

    Jquery ajax 同步阻塞引起的UI线程阻塞问题

    Jquery ajax同步阻塞问题详解 在使用Jquery进行异步数据交互时,常常会遇到ajax请求引起的问题。尤其是在同步模式下,一个请求可能会阻塞浏览器的UI线程,从而造成用户体验的严重下降。本文将详细讨论Jquery ajax...

    使用$.Ajax调用后台.aspx

    若需同步请求(阻塞执行),可将`async: false`添加到配置对象中。 六、跨域问题 默认情况下,$.ajax只允许同源策略下的请求,即协议、域名和端口必须一致。如果需要跨域,可以通过CORS(跨源资源共享)或者JSONP等...

    AJAX访问PHP函数库AJASON的同步(非异步)版

    AJASON库的同步版本修改了原有的异步行为,使得开发者可以通过更简单的方式来实现同步调用。在"examples"中,你可以找到如何使用这个库的示例代码,这对于理解和应用这个库非常有帮助。 使用AJASON库进行同步AJAX的...

    ajax调用,asp版本的 ,超级好用

    7. **异步与同步**:Ajax的异步特性意味着它不会阻塞浏览器执行其他任务。然而,如果设置为同步,浏览器将等待Ajax请求完成后再继续执行后续代码。 在ASP中实现一个简单的Ajax调用示例,可以分为客户端和服务器端两...

    Ajax简单异步调用

    Ajax(Asynchronous ...总之,Ajax简单异步调用是Web开发中的重要技术,它通过局部刷新和后台通信,实现了更加流畅和高效的用户交互体验。了解并熟练运用Ajax,对于提升网站或应用的性能和用户体验具有重要意义。

    详解socket阻塞与非阻塞,同步与异步、I/O模型

    同步和异步只关注客户端的调用机制,而阻塞和非阻塞则关乎服务端的处理方式。同步与异步的区分并不依赖于阻塞或非阻塞,它们可以结合使用。例如,客户端可以发起异步请求,然后服务端处理请求时可能采用阻塞或非阻塞...

    jquery Ajax 全局调用封装实例详解

    ### jQuery Ajax 全局调用封装实例详解知识点 #### 前言 在前端开发中,异步数据交互是核心功能之一,通常使用Ajax技术实现。当全站需要频繁进行数据交互时,如果每次都写重复的`$.ajax`代码,不仅效率低下,而且...

    浅谈js的ajax的异步和同步请求的问题

    同步Ajax请求会阻塞浏览器,导致用户体验变差,因为它会停止所有界面的交互直到请求完成。因此,除非绝对必要,否则应当避免使用同步Ajax请求。 总结来说,Ajax请求的异步与同步问题关系到JavaScript代码的执行流程...

    基于ajax相册系统

    同步请求则会阻塞浏览器,直到请求完成。在相册系统中,异步加载可以实现如图片预览、分页加载等操作,不会打断用户的浏览体验。 ### 4. jQuery与Ajax jQuery是一个流行的JavaScript库,它简化了Ajax操作。通过$....

    apex,ajax相关资料

    - **同步调用(Synchronous Calls)**:这种类型的调用会阻塞UI,直到API调用完成。虽然简单易懂,但可能导致用户界面的冻结,影响用户体验。 - **异步调用(Asynchronous Calls)**:异步调用允许在等待API响应的...

    Ajax的简单应用以及对比同步提交表格的优点

    Ajax可以通过调用这些Web服务接口来获取或更新数据,实现跨域通信。 在"MyWebSite"这个项目中,开发者可能创建了一个Web服务,用于接收和处理Ajax请求。这可能涉及到JavaScript代码中的XMLHttpRequest对象与服务器...

    ajax帮助文档ajax帮助文档

    在现代Ajax库(如axios)中,可以通过Promise链式调用来处理异步操作,或者使用async函数来实现更接近同步的编程模型。 9. **RESTful API与Ajax**:REST(Representational State Transfer)是一种网络应用程序的...

    尚筹网-加餐-Ajax的同步和异步请求1

    在同步模式下,Ajax请求会阻塞后续代码的执行,直到服务器返回响应并处理完回调函数。 **2.2 代码** 设置`async: false`可以将Ajax请求转换为同步模式: ```javascript $.ajax({ url: "test/ajax/async.html", ...

    ajax视频教程1

    同步Ajax会阻塞浏览器,直到请求完成。异步是Ajax的主要特点,允许用户在等待响应时继续与页面交互。 ### 8. Ajax的局限性 虽然Ajax提高了用户体验,但它无法缓存请求,且不利于搜索引擎优化(SEO)。对于不支持...

    AJAX 参考手册 ajax 教程

    - **异步操作**:文件上传、数据同步等,避免页面阻塞。 ### 5. jQuery 和其他库的 AJAX 功能 jQuery 提供了简化的 `$.ajax()` 函数,以及其他如 `$.get()`, `$.post()` 的快捷方法,简化了 AJAX 使用。此外,还有...

    js使用generator函数同步执行ajax任务

    在JavaScript中,异步编程是处理I/O操作(如AJAX请求)的关键,因为它允许代码在等待非阻塞操作完成时继续执行。然而,传统的回调函数模式常常导致“回调地狱”,使得代码难以理解和维护。Generator函数是ES6引入的...

    salesforce apex ajax

    同步调用将阻塞UI直到请求完成,而异步调用则允许UI继续响应用户输入,提高了应用程序的响应速度和用户体验。 ### API调用语法 API调用在Salesforce Apex AJAX中的语法简洁明了,通过对象函数和数据类型的支持,...

    ajaxTest 实用简单封装

    本文将详细介绍如何对Ajax进行简单的封装,包括GET和POST方法,以及同步和异步提交的实现,主要针对ASP.NET环境。 **1. Ajax的基础概念** Ajax的核心是JavaScript对象XMLHttpRequest,它允许开发者在不刷新整个...

Global site tag (gtag.js) - Google Analytics