0

だから私はデータベースにたくさんの行を挿入する本当に遅くて長いクエリに非同期プログレスバーを追加しようとしています。私の実装はこの例に基づいています:http://blog.janjonas.net/2012-01-02/asp_net-mvc_3-async-jquery-progress-indicator-long-running-tasks

プログレスバーのJavaScriptコードは次のとおりです

function updateMonitor(taskId, status) {
        $("#monitors").html("Task [" + taskId + "]: " + status);
    }
//other code
if (doSend == true) {
            $.post("/SendBatch/HandleBatchRequest", {
                //other code
            },
            function (taskId) {

                // Init monitors
                //breakpoint here only stops it once the "/SendBatch/HandleBatchRequest" is done. PROBLEM.
                $("#monitors").append($("<p id='" + taskId + "'/>"));
                updateMonitor(taskId, "Started");

                // Periodically update monitors
                var intervalId = setInterval(function () {
                    $.post("SendBatch/Progress", { id: taskId }, function (progress) {
                    if (progress >= 100) {
                        updateMonitor(taskId, "Completed");
                        clearInterval(intervalId);
                    } else {
                        updateMonitor(taskId, progress + "%");
                    }
                });
            }, 100);
        }       
        ,"html");

次に、Webサイトの表示部分にDIVがあります

<div id="monitors"></div>

これがコントローラーの外観です

public SendBatchController
    //some code
private static IDictionary<Guid, int> tasks = new Dictionary<Guid, int>();

public ActionResult HandleBatchRequest(
        //some code
    )
    {
        var taskId = Guid.NewGuid();
        tasks.Add(taskId, 0);



        var batchId = Guid.NewGuid().ToString("N");
        var costd = cost.ToDecimal();

        IEnumerable<BatchListModel> customers;

        try
        {
            customers = new CustomerService(_customerRepository.Session).GetCustomers(
                //some code
                );
        }
        catch (Exception err)
        {
            return Json(err.Message);
        }
        if (doSend)
        {
            var sent = 0;

            foreach (var c in customers)
            {
                try
                {
                    var usr = _customerRepository.LoadByID(c.ID);

                    var message = new ComLog
                                      {
                                          //insertions to log
                                      };

                    _comLogRepository.Save(message);
                    sent++;

                    //progress bar part inside here that is important comes here:
                    tasks[taskId] = sent;

                }
                catch (Exception e)
                {
                    Log.WriteLine("ERR:" + e);
                }

                tasks.Remove(taskId);

            }
            return Json(taskId);

        }

        return Json(customers.Count() + " customers");
    }

    public ActionResult Progress(Guid id)
    {
        return Json(tasks.Keys.Contains(id) ? tasks[id] : 100);
    }

これは動作しません。プロセスはバックグラウンドで機能します。クエリが「完了」メッセージで実行された後、DIVは表示されます。クエリ中は表示されません。非同期のものがどのように機能するかわからないので、ここで論理エラーが発生する可能性があります。たとえば、合計で何人の顧客がいるかさえ知っていますか?コードのもう1つの重要な部分は、「tasks [taskId]=sent;」です。正しく行われたかどうかはわかりません。

4

3 に答える 3

1

HandleBatchRequestJavaScript 側では、進行状況チェックを開始する関数は、リクエストが正常に完了するまで起動しません。の 3 番目のパラメータは$.post()、リクエストが成功した後に発生するものです。

C# コントローラーがすぐにタスク ID を返すようにし、データベースの挿入を別のスレッド/バックグラウンド ワーカーに渡す必要があります (これについては以下で詳しく説明します)。または、JavaScript で taskId をランダムに生成し、C# コントローラーに渡します。

そこから、ブラッドが述べたように、その中に ajax リクエストを使用して setInterval を実行したくありません。AJAX は非同期であるため、サーバーが応答を返すまでにしばらく待つことができます。複数のリクエストが一度に発生してバックエンド サーバーで元に戻すストレスが発生するのを防ぐには、次のようにします。

var taskId = 0;
$.post('/SendBatch/HandleBatchRequest', {}, function(r) {
    taskId = r;  // set task id from 
    $("#monitors").append($("<p id='" + taskId + "'/>"));
    CheckProgress();
}, 'html');

function CheckProgress() {
    $.post("SendBatch/Progress", { id: taskId }, function (progress) {
    if (progress >= 100) {
        updateMonitor(taskId, "Completed");
    } else {
        updateMonitor(taskId, progress + "%");
        setTimeout(function() {
            CheckProgress()
        }, 1000);
    }
}

C# 側では、コントローラーはすべての Web 要求でインスタンス化されるため、進行状況を確認tasksすると空になります。実際のレコードを、コントローラーからレコードを挿入する実際の作業を行う何らかのバックグラウンド ワーカー/スレッドにオフロードする必要があります。これをかなり頻繁に行っている場合は、サーバー自体にインストールされている何らかのバックグラウンド サービスを調べて、物事を最適化し、今後最高の柔軟性を提供するために継続的に実行することをお勧めします。

于 2013-02-21T21:56:11.443 に答える
0

setInterval 関数内で ajax を使用しないことを強くお勧めします。代わりに、$.post() の成功/完了コールバック関数で setTimeout を使用します。これにより、リクエストが順次生成されることが保証されます。

100 ミリ秒ごとに ajax リクエストを送信すると、同期がすぐに外れ、間違いなく問題が発生します。

于 2013-02-21T21:27:16.993 に答える
0

ローディングGIFをWebサイトに追加するだけではどうですか(ここからダウンロードできます - http://www.ajaxload.info/)次に、このローディングGIFをページのdivに配置します-表示したい場所ならどこでも。

以下のようなもの

<div><img class="hidden " id="LoadingGif" src='../Content/Styles/images/loading.gif' height="100" /></div>

次に、js ファイル simplay で、LoadingGif id に隠されているクラスを削除し、場合によっては、monitors div に隠されているクラスを追加します。

非表示のクラスは、site.css で以下のようにする必要があります

.hidden  {visibility:hidden; display:none;}
于 2013-02-24T19:58:28.743 に答える