Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   progress bar для JS (https://javascript.ru/forum/misc/3603-progress-bar-dlya-js.html)

Dagger 06.05.2009 15:12

progress bar для JS
 
Здравствуйте!
Помогите, пожалуйста, в решении следующей задачи. Бьюсь уже два дня, но ничего не выходит.

Имеется элемент div, который реагирует на событие onclick:

Код:

<div onclick='doStretch(1)'> &rt;&rt; </div>
Функция doStretch() выполняется длительное время, и для утешения пользователя нужно нарисовать progress bar. В моем случае все просто: progress bar - просто анимированный gif, который должен появиться при клике на этот div, и исчезнуть в конце работы функции doStretch():

Код:

<script language='javascript'>
  function doStretch(i) {
        initProgress();
 /* здесь идет очень долгий процесс, для которого нужно отобразить progress bar*/
        releaseProgress();
  }

  function initProgress() {
        var progressDiv = document.getElementById("stretchProgress");
        progressDiv.style.visibility = "visible";
  }

  function releaseProgress() {
        var progressDiv = document.getElementById("stretchProgress");
        progressDiv.style.visibility = "hidden";
  }
</script>

...

<body>
  <img src='images/progress.gif'  style="visibility: hidden;"  id="stretchProgress"/>

...

Однако этот прямой подход не работает. Браузер сначала полностью выполняет функцию doStretch() и только после этого отображает результат выполнения функций initProgress() и releaseProgress(), т.е. показывает и прячет картинку, символизирующую progress bar. Я понял это поведение следующим образом: браузер не скидывает свой буфер (где картинка уже стала visible) на отображение, но функции подобных flush() я в JS не нашел (я новичок в JavaScript).

Желаемый, но абсолютно неприемлемый результат получается, если написать функцию initProgress() с alert'ом:

Код:

  function initProgress() {
        var progressDiv = document.getElementById("stretchProgress");
        progressDiv.style.visibility = "visible";
                        alert("все что угодно");
  }

Т.к. alert() является блокирующим вызовом, то браузер прерывает исполнение скрипта и выводит текущий результат на экран, а затем уже продолжает выполнять сценарий после исчезновения alert'а. Но alert, как вы понимаете, здесь недопустим, а других блокирующих вызовов типа sleep(), насколько я знаю, в JavaScript нет.

Может кто-нибудь знает, как можно выйти из этой ситуации? Помогите, пожалуйста.

ZoNT 06.05.2009 15:15

я бы предложил тебе привести сюда код функции doStretch, и мы бы помогли тебе её оптимизировать, чтобы она выполнялась быстро.

Kolyaj 06.05.2009 15:24

Браузер все равно будет зависать, и никакого анимированного гифа все равно не будет видно.

Dagger 06.05.2009 15:26

Проблема в том, что у меня используется тулзовина (CodeThatGrid), которая позволяет генерить интерактивные гриды, как в Excel'е. Функция doStretch() должна пройтись по строке с индексом i и выставить в каждую ячейку некоторое значение (распространить одно и то же введенное пользователем значение). Ситуация становится критической, когда грид содержит большое число столбцов (это необходимо заказчику).

Вот сама функция:
function doStretch(i) {
  initProgress();

      if ( !(cg instanceof CCodeThatGrid) ) return;
      if ( Undef(window.lastStretchPositions) ) 
	window.lastStretchPositions = new Array(NUM_ROWS - 1);

  var lastVisibleCellIndex = getLastVisibleCellIndex();
  var stretchVal, stretchInitialPos;
      for ( var j = 3; j <= lastVisibleCellIndex; j++ ) {
              if ( Undef(cg.cells[i][j]) ) continue;
          var currentVal = parseFloat( cg.cells[i][j].getData() );
    	   if ( isNaN(currentVal) ) continue;
          stretchVal = currentVal;
          stretchInitialPos = j;
      }     
      if ( Undef(stretchInitialPos) ) return;
      if (stretchInitialPos + 1 > lastVisibleCellIndex) return; 
      if ( Def(window.lastStretchPositions[i]) ) {
          delete lastStretchPositions[i];					
      }			
  window.lastStretchPositions[i] = new Array();
  var index = 0;
      for ( var j = stretchInitialPos + 1; j <= lastVisibleCellIndex; j++ ) {
      	  if ( Undef(cg.cells[i][j]) ) break;
      	  if ( cg.cells[i][j].col.isReadOnly || cg.cells[i][j].isReadOnly ) continue;
           cg.cells[i][j].setData(stretchVal);	
      	window.lastStretchPositions[i][index] = j;
      	index++;
      }
  releaseProgress();
}


И вот та ее часть, которая отрабатывает мучительно долго:

...
      for ( var j = stretchInitialPos + 1; j <= lastVisibleCellIndex; j++ ) {
      	  if ( Undef(cg.cells[i][j]) ) break;
      	  if ( cg.cells[i][j].col.isReadOnly || cg.cells[i][j].isReadOnly ) continue;
           cg.cells[i][j].setData(stretchVal);	
      	window.lastStretchPositions[i][index] = j;
      	index++;
      }
  releaseProgress();
}

Gvozd 06.05.2009 15:26

?
function doStretch(i) {
	initProgress();
	setTimeOut(function(){
	/* здесь идет очень долгий процесс, для которого нужно отобразить progress bar*/
	 releaseProgress();
	},500);
 
  }

  function initProgress() {
	var progressDiv = document.getElementById("stretchProgress");
	progressDiv.style.visibility = "visible";
  }

  function releaseProgress() {
	var progressDiv = document.getElementById("stretchProgress");
	progressDiv.style.visibility = "hidden";
  }

Dagger 06.05.2009 15:27

Неужели нет никакого способа отрисовать progress bar?

Dagger 06.05.2009 15:30

Gvozd,
Большое спасибо! Действительно, это помогло. :)

ZoNT 06.05.2009 16:15

Судя по коду функции торомоза складываются в цикле из-за медленой функции (либо Undef, либо setData). Надо попрофилировать выполнение да посмотреть, что тормозит...

Gvozd 06.05.2009 16:34

Firebug и console вам в помощь:
console.time(name)
console.timeEnd(name)

ZoNT 06.05.2009 16:41

Firebug и профилировщик, встроенный в него вам в помощь!


Часовой пояс GMT +3, время: 14:27.