鸟食轩

 Microsoft .NET[C#] MVP 2003
随笔 - 424, 文章 - 232, 评论 - 5416, 引用 - 344
数据加载中……

Ajax基石脚本异步并发调用参数传递

    在Ajax开发框架中,最基本的划分是服务器端和客户端。服务器端相对来说比较简单,只要是可以开发动态网页的语言都可以胜任;客户端浏览器就是JScript/JavaScript的天下了,好像没有看到有VBScript做的Ajax客户端库,就算它只支持IE。由于客户端依赖于脚本并运行在浏览器中,似乎比服务器端的可实现和可管理性还要差些。

    这里我说一下Ajax中的A, Asynchronous调用的一些问题。如果我们在异步调用时不为方法传递任何的参数,那么这个问题也就简单甚至不存在了。但是事实上,我们开发一些稍微复杂些的功能时,对于"脚本异步并发调用参数传递"这个功能是很需要的。说的严重些,可以把这个功能看成Ajax客户端框架能否真正Asynchronous的基石。对于异步调用参数传递的问题,可以看我以前的一篇文章"使用匿名函数为setInterval传递参数"。虽然文中的示例很好地解决了参数传递问题,但是我们看看下面的示例,看会发现什么呢?

function foo()
{
    
var param = 100;
    window.setTimeout(
function()
    
{
        intervalRun(param);
    }
0);
    param 
= 0;
}


function intervalRun(times)
{
    alert(times);
}

    我们执行foo,会得到什么样的alert结果呢?100? or 0?,答案是:0。其实写过内嵌函数就知道,这里要真确的传入100,需要这样改写foo方法:
function foo()
{
    
var param = 100;
    
var __param = param;
    window.setTimeout(
function()
    
{
        intervalRun(__param);
    }
0);
    param 
= 0;
}
// 这样添加一个变量来存储param就可以了,这下执行foo得到的alert结果就是:100。

    上面这个修正本身没有问题,可是如果我在并发执行的情况下,就可能又有新的问题。示例代码:
function doTick()
{
    
var tick = new Date().getTime();
    var __tick = tick;
    
var foo = function()
    
{
        GetTick(__tick);
    }
;
    
window.setTimeout(foo, 3000);
}


function GetTick(tick)
{
    
// to do something depend on tick parameter
}

    当我们在调用doTick方法时,如果以小于3000ms的频率并发,将会导致前一次的tick变量被后面执行的执行过程修改的问题,从而导致GetTick方法取到错误的tick参数。也就是说必须把doTick方法看成一个,需要"本身执行时间+3000ms"才能运行完的方法,然后再保证并行的执行doTick方法才不会出错。这样的限制条件显然是不可接受的,那么我们该怎么办呢?

    其实我们只需要使用内嵌函数自身帮助我们传递参数就行了,修改后的示例如下:
function doTick()
{
    
var tick = new Date().getTime();
    
var foo = function()
    
{
        
var __tick = foo.params[0];
        GetTick(__tick);
    }
;
    foo.params 
= [tick];
    window.setTimeout(foo, 
0);
}

    由于内嵌函数构造出一个Closure Scope,它将帮组我们保存参数的Context,使我们获得真正的"异步并发调用参数传递"效果。

    注意:Closure Scope是JScript编程中危险的高级技术,使用不当极易造成IE Memory Leak。

posted on 2006-03-10 19:10 birdshome 阅读(3696) 评论(8)  编辑 收藏 所属分类: Jscript&Dhtml开发

评论

#1楼    回复  引用  查看    

唉,前一段俺也被IE内存泄露的问题搞了一把,归根结底都是COM引用计数搞的鬼。
2006-03-12 21:15 | Nomagic      

#2楼    回复  引用    

<script language="JavaScript">
var portletReq,portletReqUser;
var type;
function asynchGet(updateURL,typePara){
type = typePara;
if (typePara == "patient"){
if (window.XMLHttpRequest) {
portletReq = new XMLHttpRequest();
} else if (window.ActiveXObject) {
portletReq = new ActiveXObject("Microsoft.XMLHTTP");
}
portletReq.onreadystatechange = processReqChange;
if (!document.usageForm.spanID.options[0].selected)
updateURL = "${pageContext.request.contextPath}/run?__report=patients_changes_groupbyday.rptdesign";
updateURL = updateURL+"&startday="+startDayStr+"&endday="+enddateStr;


portletReq.open("GET", updateURL, true);
portletReq.send(null);


}
if (typePara == "user"){
if (window.XMLHttpRequest) {
portletReqUser = new XMLHttpRequest();
} else if (window.ActiveXObject) {
portletReqUser = new ActiveXObject("Microsoft.XMLHTTP");
}
portletReqUser.onreadystatechange = processReqChangeUser;
if (!document.usageForm.spanID.options[0].selected)
updateURL = "${pageContext.request.contextPath}/run?__report=user_changes_groupbyday.rptdesign";
updateURL = updateURL+"&startday="+startDayStr+"&endday="+enddateStr;
portletReqUser.open("GET", updateURL, true);
portletReqUser.send(null);
}

}
function processReqChangeUser(){
var divUser = document.getElementById("UserChangesperHour");
divUser.innerHTML="<b style='color:red;font-size:9pt;'>loading...<b>";

if (portletReqUser.readyState == 4) {
if (portletReqUser.status == 200) {
// process response
displayInvoiceUser();
}else {
divUser.innerHTML="There was a problem retrieving the XML data:" + portletReqUser.statusText;
}
}
}
// Generic AJAX function
// process the response when available
function processReqChange() {
var div = document.getElementById("PatientChangesperHour");
div.innerHTML="<b style='color:red;font-size:9pt;'>loading...<b>";

if (portletReq.readyState == 4) {
if (portletReq.status == 200) {
// process response
displayInvoice();
} else {
div.innerHTML="There was a problem retrieving the XML data:" + portletReq.statusText;
}


}
}

function getAJAXcontent(url,typePara) {
asynchGet(url,typePara);

}
function displayInvoiceUser(){
var divUser = document.getElementById("UserChangesperHour");
//div.innerHTML = "";
divUser.innerHTML = portletReqUser.responseText;
if (divUser.childNodes[0].childNodes[1] != null){
divUser.childNodes[0].childNodes[1].innerHTML="";
}
else{
divUser.innerHTML = "<b style='color:red;font-size:9pt;'>can't find record by that Criteria<b>";
}

delete portletReqUser['onreadystatechange'];
portletReqUser = null;
}
function displayInvoice() {
// substitute new invoice HTML content into "portletcontent" <div> tag
var div = document.getElementById("PatientChangesperHour");
//div.innerHTML = "";
div.innerHTML = portletReq.responseText;
var obj = portletReq.responseText;
if (div.childNodes[0].childNodes[1] != null){
div.childNodes[0].childNodes[1].innerHTML="";

}
else{
div.innerHTML = "<b style='color:red;font-size:9pt;'>can't find record by that Criteria<b>";
}

delete portletReq['onreadystatechange'];
portletReq = null;
}
function queryUser()
{
getAJAXcontent('${pageContext.request.contextPath}/run?__report=user_changes.rptdesign','user');
}
</script>
调用时就会产生,异步并发参数传递冲突问题,我于是设1000ms为间隔,能不能用你的方法改写那。我没看懂你写的方法。
<input type="button" onclick="getAJAXcontent('${pageContext.request.contextPath}/run?__report=patients_changes.rptdesign','patient');setTimeout('queryUser()',1000)" name="graph" value="Graph">
2006-03-28 13:48 | baoshaoming [未注册用户]

#3楼    回复  引用    

先谢谢了,如果你能恢复一下。
2006-03-28 13:50 | baoshaoming [未注册用户]

#4楼 [楼主]   回复  引用  查看    

@baoshaoming
"异步并发参数传递冲突问题",能说一下上面的代码中,你发现了那个函数的那个参数出现了传递冲突吗?
2006-03-28 15:30 | birdshome      

#5楼    回复  引用    

其实在实际运用中,AJAX过于复杂,谁能解决好这个问题,就是谁对
WEB开发的一个很大的贡献,我在遇到这种问题时候,都是采用我自己的一个比较独特的方法.不是很聪明,但是很实用.
2006-04-11 05:33 | lilo [未注册用户]

#6楼    回复  引用  查看    

这个本身是设计的问题.
如果你打算函数执行时参数是最后,那个,就应该把参数保存到可访问的位置(例如全局),而不是作为param出现.
2006-04-25 21:53 | Lostinet      

#7楼    回复  引用    

楼主,能写段代码演示这个错误么?
我怎么试doTick,多次调用,都没有出现参数不正确
2007-02-21 21:42 | 1234 [未注册用户]

#8楼    回复  引用    

楼主的博客简直就是javascript的百科全书,令我爱不释手!希望能继续看到楼主的精彩文章!恩泽大众!
2008-03-14 02:24 | helloshp [未注册用户]

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-03-11 21:15 编辑过


相关链接:

历史上的今天:
2005-03-10 单扫描的JScript版String.Format方法