我在开发中,有一个恢复网站的操作,比较耗时,我想在操作时往缓存中记录当前操作进度,然后另一个请求获取当前操作的进度即时显示在客户端显示。问题:是另一个请求不能即时显示进度,而只是最后一次请求才可以改变进度条。类似代码 WebService.ashx(c#):
public class WebService : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            string invoke = string.Empty;
            string jsoncallback = string.Empty;            if (!string.IsNullOrEmpty(context.Request["invoke"]))
                invoke = context.Request["invoke"].ToString().Trim();
            if (!string.IsNullOrEmpty(context.Request["jsoncallback"]))
                jsoncallback = context.Request["jsoncallback"].ToString().Trim();            context.Response.ContentType = "application/x-javascript; charset=utf-8";
            switch (invoke.ToLower())
            {
                case "call":
                    int currentValue = 0;
                    int TotalValue = 100;
                    HttpContext.Current.Cache.Remove("progress");
                    HttpContext.Current.Cache.Insert("progress", currentValue + "," + TotalValue, null, 
                        DateTime.Now.AddMinutes(60),System.Web.Caching.Cache.NoSlidingExpiration);                    for (int i = 1; i <= TotalValue; i++)
                    {
                        currentValue = i;
                        //TODO...
                        HttpContext.Current.Cache.Insert("progress", currentValue + "," + TotalValue, null,
                            DateTime.Now.AddMinutes(60), System.Web.Caching.Cache.NoSlidingExpiration);
                        Thread.Sleep(100);
                    }
                    context.Response.Write(string.Format("{0}({{error:{1}, message:\"{2}\"}})", jsoncallback, false.ToString().ToLower(), "finished."));
                    break;
                case "progress":
                    string progress = "100,100";
                    if(HttpContext.Current.Cache["progress"] != null)
                    {
                        progress = HttpContext.Current.Cache["progress"].ToString();
                    }
                    context.Response.Write(string.Format("{0}({{error:{1}, message:\"{2}\"}})", jsoncallback, false.ToString().ToLower(), progress));
                    break;
                default:
                    context.Response.Write(string.Format("{0}({{error:{1}, message:\"{2}\"}})", jsoncallback, false.ToString().ToLower(), "parameter error."));
                    break;
            }
        }        public bool IsReusable
        {
            get{return false;}
        }
    }页面代码:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 <style>
.ProgressBar {
position:relative;
margin-top:30px; 
margin-bottom:20px;
margin-left:240px;
width: 220px;
border: 1px solid #B1B1B1;
overflow: hidden;
}
.ProgressBar div {
position:relative;
background: #2BD029;
color: #333333;
height: 15px;
line-height: 15px;
text-align:left;
}
.ProgressBar div span {
position:absolute;
width: 220px; 
text-align: center;
font-weight: bold;
}
 </style>
 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
 <script type="text/javascript">
var intervalID; function RequestProcess(){
$.getJSON("http://localhost:4397/webservice.ashx?invoke=progress&jsoncallback=?", function(data) {
var progress = data.message;
var position = parseInt(progress.split(",")[0] / progress.split(",")[1] * 100);
if(isNaN(position))
position = 0;
$('#divMessage').append("<br/>"+position);
if (position >= 100) stopRequestProcess();
$('.ProgressBar > div').css({ "width": position + "%" });
$('.ProgressBar > div > span').html(position + "%");
$('#ProgressInfo').html(position >= 100 ? "finished" : position);
});
}
function stopRequestProcess(){
clearInterval(intervalID);
} $(document).ready(function(){
$('#btnStart').click(function(){
$('#divMessage').html('');
$.ajax({
type: "GET",
url: "http://localhost:4397/webservice.ashx?invoke=call&jsoncallback=?",
dataType: "jsonp",
async: false,
error: function(xhr, ajaxOptions, thrownError) {
stopRequestProcess();
},
success: function(response) {
stopRequestProcess();
$('.ProgressBar > div').css({ "width": "100%" });
$('.ProgressBar > div > span').html("100%");
$('#ProgressInfo').html("finished");
}
}); intervalID = setInterval(RequestProcess, 500); 
});
});
 </script>
 </head> <body>
<div>
<div>
<div class="ProgressBar" style="*margin-left:0px"  align="left">
    <div style="width:0%;*margin-left:0px"><span>0%</span></div>
</div>
<div id="ProgressInfo" class="ProgressInfo">processing...</div>
</div>
<button id="btnStart" name="btnStart">start</button>
</div>
<br/>Progress Information:<br/>
<div id="divMessage"></div>
 </body>
</html>

解决方案 »

  1.   


    如图:前面的6,11,15,21...进度取到后不能即时显示出来,而到100时才显示100%和finished字符。另外用蹩脚的英文发了一个蹩脚的帖子:
    http://stackoverflow.com/questions/3690351/how-to-show-progress-immediately-using-ajax
      

  2.   

    这样是不行的,只有Response结束的时候才能触发Ajax的SuccessCallBack,你在Response.Write的时候并没有结束Response。建议你另做一个定时的Ajax(比方说20秒),这个Ajax用于检测当前的进度,然后返回进度的信息,并显示在processBar上。
      

  3.   

    to theforever:
        帖子第一句我说明了思路,只是可能简单了一些,导致你没明白。下面我重新描述一下。
        另外,我的代码是完整的实例代码。
    to wdzr_826:
        可能是我没讲清楚我的实现, 我的代码跟你说的是一样的。情况是这样:
    就是做一个网站备份恢复的功能,要恢复操作时需要耗时比较久(备份也一样),就像我上面的示例代码。
    有一个web service,提供了2个操作,一个耗时很长的操作(包含把当前操作进度写入cache中),一个是获取当前进度的操作(从cache中获取当前进度)然后客户端请求耗时长的web service时,会定时ajax请求获取当前进度并修改进度条( intervalID = setInterval(RequestProcess, 500); )问题时,在请求耗时长的web service同时,ajax也会获取当前进度并能返回,但就是不能改变进度条,直到最后一次才行。stackoverflow.com上有人的实例貌似,我试试再说。
      

  4.   


    一个ajax负责backup工作,可以在后台用一个线程模拟备份工作。将备份的进度保存在缓存中:session、application等
    一个ajax用setTimeout、setInterval定时向服务器获取backup进度
      

  5.   

    有些不太明白... 你的 很多个Ajax 请求的是同一个后台线程?? 或者你有其它的方法
      

  6.   


    大略看了一下,你最后一次才行,是因为在那个请求主体的AJAX的SUCCESS事件里写入100%.这是自然会成功的.
    但为了获得中间的进度值,你还使用了另外一个$.getJSON.而这个的调用,intervalID = setInterval(RequestProcess, 500); 位置在$.ajax后面,这也没问题. 但问题是,你的$.ajax使用了"async: false,",这个是同步的方式.只有接收完毕,才能向下执行到intervalID = setInterval(RequestProcess, 500);这样的话,你取的进度还是已经完成的100%. 就是目前的现象了.所以,这个只要把$.ajax的参数改成 async: true,就可以了.
      

  7.   

    你可以玩玩日本人写的javascript多线程库
    Concurrent.Thread.js
      

  8.   

    好多天没来了,感谢大家的关注。
    刚才在家里电脑试了一下,我上面的代码在IE6、360浏览器(传说是IE7内核),Chrome都正常,符合我的要求,而在Firefox不行。to IBM_hoojo:
      我的代码是符合你要求的。只是backup工作没有用独立线程处理,最重要的是backup操作要马上返回结果,用线程进行后续处理。to theforever:
      你说的是错的,我以前用过async: true,也一样效果。 我想的是备份操作要马上返回结果,后续操作用其他方式继续进行(如线程处理)to daxuejianku:
      谢谢你的提议,抽空我学习一下,不过你给的这个对我应该是没用。
    谢谢大家关注。 我想stackoverflow上面Darin Dimitrov提到的是最好解决办法,我把他的代码修改用jsonp形式,在IE6、360浏览器(传说是IE7内核)、Chrome、Firefox都满足我的要求。