2017-11-15 38 views
0

kendoGridを使用しているアプリケーションで、選択した行をdbに保存した後に更新します。ループ内のループ内のループ内のループ内でループ内のプログレスバーを更新する方法

私たちは時には1000以上の行を持っているので、アプリケーションを動かさないために行を分割する必要があります。これはかなり長い時間がかかりますので、ユーザーが更新プログラムの進捗状況を確認できるようにプログレスバーを表示したかったのです。

問題は、各繰り返しで進行状況バーが更新されないことです。私はクロムデバッガを使用してステップを進めるので、私はプログレスバーの更新を見ることができます。しかし、私はリアルタイムでスクリプトを実行すると何も起こりません。

HTML

<div id="progressbar-wrapper"> 
    <div id="progressbar-outer" style="display: table;margin: 0 auto;background-color: #FFFFFF;border: 5px solid #000000;width: 50%;height: 30px;opacity: 1;z-index: 9998"> 
     <div id="progressbar" style="float:left;width: 0;height: 30px;background-color:#000000;border: 0;opacity: 1;z-index: 99999"> 
     </div> 
    </div> 
    <div id="loading-animation" style="position: fixed;top: 150px;left: 0;height: 120px;width: 100%;font-size: 100px;line-height: 120px;text-align: center;color: #000000;z-index: 9999;"> 
     ...SAVING...<br /><small>Saving Lines</small> 
    </div> 
</div> 

JAVASCRIPT

var progressbar = {}; 
$(function() { 

    progressbar = { 

     /** initial progress */ 
     progress: 0, 

     /** maximum width of progressbar */ 
     progress_max: 0, 

     /** The inner element of the progressbar (filled box). */ 
     $progress_bar: $('#progressbar'), 

     /** Method to set the progressbar. 
     */ 
     set: function (num) { 
      if (this.progress_max && num) { 
       this.progress = num/this.progress_max * 100; 
       console.log('percent: ' + this.progress + '% - ' + num + '/' + this.progress_max); 
       this.$progress_bar.width(String(this.progress) + '%'); 
      } 
     }, 

     fn_wrap: function (num) { 
      setTimeout(function() { 
       this.set(num); 
      }, 0); 
     } 

    }; 

}); 



var processedPartitions = 0; 
var partitions = saveData.partition(30); //saveData is the selected saved rows 

//Iterate through partitions 
for (var i = 0; i < partitions.length; i++) { 

    var urlForWindow = "/Data/Save/"; 
    $.ajax({ 
     url: urlForWindow, 
     type: "POST", 
     dataType: 'json', 
     contentType: 'application/json; charset=utf-8', 
     data: JSON.stringify(partitions[i]), 
     async: true, 
     complete: function() { 
      processedPartitions++; 
      if (processedPartitions === partitions.length) { 

       //PROGRESS BAR (DOESNT WORK, Doesnt show or update the progressbar in real time) ========================================== 

       //Get the full number of rows getting updated. 
       var iterations = 0; 
       for (var i = 0; i < partitions.length; i++) { 
        iterations = iterations + partitions[i].length; 
       } 

       //add total number of records to update as the iterations 
       progressbar.progress_max = iterations; 

       //make the progress bar visable before updating //does not show 
       $("#progressbar-wrapper").css("display", "block"); 

       //start counter of rows updated 
       var recordsUpdated = 0; 

       //begin update loop 
       var mainGrid = $("#mainGrid").data("kendoGrid"); 
       $.each(mainGrid.dataSource.data(), function() { 

        if (this.RowSelected === true) { 

         for (var i = 0; i < partitions.length; i++) { 
          for (var j = 0; j < partitions[i].length; j++) { 

            var row = mainGrid.dataSource.getByUid(this.uid); 
            row.set("RowSelected", "false"); 
            row.set("dirty", "false"); 

            //after update iterate recordsupdated 
            recordsUpdated++; 

           //update the progress bar if not complete //doesnt update in realtime 
           if (iterations >= recordsUpdated) { 
            progressbar.set(recordsUpdated);   
           } 
          } 
         } 
        } 
       }); 

       //turn off progressbar after complete // never shows in realtime, never shown closing 
       $("#progressbar-wrapper").css("display", "none"); 

       //Success message 
       alert("Saved"); 
      } 

     }, 
     error: function (jqXHR, textStatus, errorThrown) { 
      alert(jqXHR.resonseText); 
     } 
    }); 
} 

だから私はすべてが動作することを確認することができ、線でコード行をステップ実行。しかし、リアルタイムで実行しているとき。プログレスバーは決して表示されません。そのページ全体が凍っているようです。

+1

Ajaxをループするためにintervalまたはtimeoutを使用しないでください。 ajax呼び出しの成功または完了から次のajaxを実行する関数を呼び出します。そこからもsetTimeoutを使うことができますが、ループ内にajaxをラップしません。 – mplungjan

+2

ブラウザはシングルスレッドです。バーはjsが停止するまで更新されません。 –

+0

ジョナスが言ったこと。実際に理解できる価値のあるものは、イベントループです:https://www.youtube.com/watch?v=8aGhZQkoFbQ – Xeraqu

答えて

0

だから私はそれを理解しました。ちょうど2つのプロセスを分離しなければならなかった。 ajaxは完了し、イベントループを使用してグリッドを更新するためにcompleteフラグを次のメソッドに送ります。

//Get the number of saved data rows. That = total iteration 
var iterations = saveData.length; //get data 

var processedPartitions = 0; 
var partitions = saveData.partition(30); partition data 

//write buyer to Database First (Quickest method) 
for (var p = 0; p < partitions.length; p++) { 
    var urlForWindow = "/Data/Save/"; 
    $.ajax({ 
     url: urlForWindow, 
     type: "POST", 
     dataType: 'json', 
     contentType: 'application/json; charset=utf-8', 
     data: JSON.stringify(partitions[p]), 
     async: true, 
     beforeSend: function() { 

     }, 
     success: function (result) { 
      successComplete = 1; //1 means success 
     }, 
     complete: function() { 
      processedPartitions++; 
      //check if all partitions processed 
      if (processedPartitions === partitions.length) { 
       successComplete = successComplete + 1; //2 means successful completion 
      } 
     }, 
     error: function (jqXHR, textStatus, errorThrown) { 
      alert(jqXHR.resonseText); //0 means error 
     } 
    }); 
} 


//PROGRESS BAR ================================================ 
//max progress bar 
progressbar.progress_max = iterations; 

var mainGrid = $("#mainGrid").data("kendoGrid"); 

var i = 0; //partition # 
var j = 0; //line # 
var linesUpdated = 0; //update complete # 


//make the progress bar visable before updating 
$("#progressbar-wrapper").css("display", "block"); 


//then loop through update grid methods 
(function innerloop() { 

    try { 
     //If end 
     var testPart = (partitions[i].length - 1); //30 but starts at 0 
    } catch (err) { 
     //exit loop 
     return; 
    } 

    //Get the length of the partition 
    var thisPartitionLength = (partitions[i].length - 1); //30 but starts at 0 


    if (thisPartitionLength >= j && successComplete === 2) { 

     $.each(mainGrid.dataSource.data(), 
      function() { 

       if (this.RowSelected === true) { 

        //get id 
        var row = mainGrid.dataSource.getByUid(this.uid); 

        //unselect and turn off dirty 
        row.set("RowSelected", "false"); 
        row.set("dirty", "false"); 
        linesUpdated++; 
       } 
      }); 
     //update line # 
     j++; 
     //update progressbar 
     progressbar.set(linesUpdated); 
    } 

    if (j <= thisPartitionLength) { 
     //loop if not complete with partition 
     setTimeout(innerloop, 0); 
    } else { 
     if (j > thisPartitionLength) { 
      //if end of partition reset the line # and increase partition # and continue loop 
      i++; 
      j = 0; 
      setTimeout(innerloop, 0); 
     } 

     //on complete 
     if (linesUpdated === iterations) { 

      //Success message 
      alert("Saved"); 
     } 
    } 
})(); 

UPDATE

うわ!これはIE11では動作しません!

0

javascriptがシングルスレッドであると同時に複数のタスクを実行することはできません。しかし、HTML5はWebワーカーを導入しました。ウェブワーカーで要件を満たすことができるので、バックグラウンドスレッドをサーバーの相互作用に使用することができます。メインスレッドはUI更新に余裕があります。

Web workers