如何使用ajax立即显示进度?

时间:2010-09-11 08:40:12

标签: jquery ajax progress

我有一个使用jQuery ajax调用Web服务的演示,同时,另一个请求显示了进度。

为什么它不立即显示进度,而最后显示所有进度。 像这样的代码: 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 个答案:

答案 0 :(得分:2)

关于您的代码的几点评论:

  1. 您需要启动一个新线程来执行冗长的操作并立即返回而不是阻止工作线程
  2. 您正在使用缓存来跟踪进度,这是不可靠的。 ASP.NET可以在不同情况下驱逐缓存,例如内存不足等......
  3. 以下是我提出的一个例子:

    public class WebService : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "application/x-javascript";
            var id = context.Request["id"];
    
            if (string.IsNullOrEmpty(id))
            {
                id = Guid.NewGuid().ToString();
                context.Application[id] = 0;
                new Thread(() =>
                {
                    for (int progress = 0; progress < 100; progress++)
                    {
                        context.Application[id] = progress;
                        Thread.Sleep(100);
                    }
                    context.Application.Remove(id);
                }).Start();
            }
    
            var serializer = new JavaScriptSerializer();
            context.Response.Write(serializer.Serialize(new
            {
                id = id,
                error = false,
                progress = context.Application[id] ?? 100
            }));
        }
    
        public bool IsReusable
        {
            get { return false; }
        }
    }
    

    客户:

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <title>Test</title>
    <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 = null;
        $(function () {
            $('button').click(function () {
                $(this).attr('disabled', 'disabled').text('processing...');
                $.getJSON('/webservice.ashx', function (result) {
                    intervalId = setInterval(function () {
                        poll(result.id);
                    }, 1000);
                });
    
            });
        });
    
        function poll(taskId) {
            $.getJSON('/webservice.ashx', { id: taskId }, function (result) {
                if (result.progress >= 100) {
                    clearInterval(intervalId);
                    $('button').removeAttr('disabled').text('start');
                }
                $('#progress').html(result.progress + '%');
            });
        }
    </script>
    </head>
    <body>
        <button>start</button>
        <div id="progress"></div>
     </body>
    </html>