Как показать прогресс сразу с помощью AJAX? - PullRequest
2 голосов
/ 11 сентября 2010

У меня есть демонстрационная программа, использующая jQuery ajax для вызова веб-службы , одновременно , другой запрос показывает прогресс.

Почему бы не показать прогресс сразу, а последний показать весь прогресс. Код как это: 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 Ответ

2 голосов
/ 11 сентября 2010

Пара замечаний по поводу вашего кода:

  1. Вам нужно запустить новый поток, чтобы выполнить длительную операцию, и немедленно вернуться, а не блокировать рабочий поток
  2. Вы используете кэш для отслеживания прогресса, который не является надежным. ASP.NET может высвободить кеш при различных обстоятельствах, таких как, например, недостаток памяти и т. Д. *

Вот пример, который я привел:

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>
...