Подтвердить что ты не робот

Почему индикатор Progress Bar динамически не меняется в отличие от Text?

Я динамически обновляю несколько элементов после функции setTimeout(). Функция jQuery .text(), как представляется, динамически обновляется при каждом изменении индекса массива при обработке. Но индикатор прогресса bootstrap, который изменяется с помощью .css() и .attr(), как представляется, не динамически обновляется. Вот моя страница: http://imdbnator.com/process.php?id=f144caf0843490c0d3674113b03da0c5&redirect=false

Вы можете видеть, что текст изменяется, но индикатор выполнения заканчивается только после завершения всей функции setTimeout(). Кроме того, если я установил delay = 1000. Оно работает. Но он замедляется приложением. Поэтому мне нужно delay = 0. Но почему не изменяется прогрессбар?

Вот мой фрагмент

function launch(a) {
    var inc = 0;
    var maxc = a.length;
    var delay = 0; // delay milliseconds
    var iID = setInterval(function () {    
        var index = inc;
        var movie = a[inc];    
        //start processing function    
        //styling while processing                
        var markerPer = ((index + 1) / rawListNum) * 100; // marker percentage
        $("#procNum").text("(" + (index + 1) + "/" + rawListNum + ")"); //Processing number
        $("#procMovie").text(movie); //Processing Name
        $("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer); // progress bar -> DOES NOT WORK    
        if (++inc >= maxc) clearInterval(iID);    
    },
    delay);
}
4b9b3361

Ответ 1

В качестве объяснения, многие ответы указывают на то, что большинство браузеров запускают JavaScript в потоке пользовательского интерфейса, поэтому они не могут обновить интерфейс при выполнении JavaScript. Вместо этого браузер будет ждать завершения Javascript и вернуть управление потоку пользовательского интерфейса.

Хотя это важно иметь в виду, он не вступает в игру для вашего кода. Если вы обновили индикатор выполнения, сделав что-то вроде этого:

for (i = 0; i < len; i++) {
    updateProgressBar(i)
};

Тогда это, безусловно, помешает обновлению пользовательского интерфейса до конца.

Но вы уже поступаете правильно, используя setTimeout или setInterval, которые имеют асинхронные обратные вызовы в код. Это означает, что JavaScript может приостановить достаточно долго, чтобы вытащить любые сообщения пользовательского интерфейса. Об этом свидетельствует тот факт, что текст может динамически обновляться.

Как ваш вопрос спрашивает, почему, если пользовательский интерфейс обновляется, индикатор прогресса также не обновляется?

Ответ заключается в том, что Bootstrap применяет следующий CSS к индикатор выполнения:

.progress-bar {
  -webkit-transition: width .6s ease;
       -o-transition: width .6s ease;
          transition: width .6s ease;
}

Когда задержка между вызовами составляет 0 мс, браузер делает, время обновления пользовательского интерфейса, но не имеет время для завершения перехода CSSMS на 600 мс. Следовательно, вы не видите анимацию до конца.

Как OhAuth указывает,, вы можете запретить браузеру задерживать обновление ширины, удалив эффект перехода с помощью CSS следующим образом:

.progress .progress-bar {
  -webkit-transition: none;
       -o-transition: none;
          transition: none;
}

Если вы перебираете множество элементов, инкрементные обновления будут предоставлять некоторую анимацию. Если вы хотите уйти от стиля для универсального варианта использования, вы можете включить и выключить переходы в своем коде. Начиная с jQuery 1.8 вы можете обновлять свойства CSS без префикса поставщика, поэтому вам просто нужно позвонить .css("transition","none").

Конечно, в зависимости от того, сколько работы вы делаете для каждого фильма, JavaScript может быть закончен, прежде чем вы сможете визуально обнаружить все изменения пользовательского интерфейса, и в этом случае продление задержки не повредит. Если вы хотите протестировать более длительные процессы, вы можете использовать следующую функцию сна:

function sleep(sleepyTime) {
  var start = +new Date;
  while (+new Date - start < sleepyTime){}
}

Здесь вы можете поиграть там, где каждый параметр - это переменная, которую вы можете настроить, чтобы увидеть, как она будет реагировать, но лучшим вариантом является только условное удаление переходов.

Демонстрация в фрагментах стека

var delay, numMovies, throttledMovies, sleepTime, removeTransition;

$("#delay").change(function(){ delay = this.value }).change()
$("#movies").change(function(){ numMovies = this.value }).change()
$("#sleep").change(function(){ sleepTime = this.value }).change()
$("#transition").change(function(){ removeTransition = this.checked }).change()

$("#loadMovies").click(loadMovies);

function loadMovies() {
  var i = 0;
  
  throttledMovies = Movies.slice(0, numMovies)
  
  if (removeTransition) {
    $('#progress-bar-movie').css("transition","none");
  }
  
  var interval = setInterval(function () {
    loadMovie(i)

    if (++i >= numMovies) {
      clearInterval(interval);
      $('#progress-bar-movie').css("transition","width .6s ease");
    }
  }, delay);
};

function loadMovie(i) {
  var movie = throttledMovies[i];
  var percentComplete = ((i + 1) / numMovies) * 100;

  sleep(sleepTime);
  
  // update text
  $("#procNum").text("(" + (i + 1) + "/" + numMovies + ")");
  $("#procMovie").text(movie.Title); 

  // update progress bar
  $('#progress-bar-movie')
    .css('width', percentComplete+'%')
    .attr('aria-valuenow', percentComplete);
};

function sleep(sleepyTime) {
  var start = +new Date;
  while (+new Date - start < sleepyTime){}
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<script src="http://kylemitofsky.com/libraries/libraries/movies.js"></script>

<!-- params -->
<label for="delay">Delay (ms)</label>
<input type="number" value="0" min=0 max=1000 id="delay"/>
<label for="movies"># Movies </label>
<input type="number" value="250" min=0 max=250 id="movies"/>
<label for="sleep">Sleep time (ms)</label>
<input type="number" value="0" min=0 max=1000 id="sleep"/>
<label for="transition">Remove transition? </label>
<input type="checkbox" checked="true" id="transition"/><br/><br/>

<button class="btn btn-primary btn-lg" id="loadMovies">
  Load Movies
</button><br/><br/>

<p>
  <b>Current Title</b>: <span id="procMovie"></span><br/>
  <b>Progress</b>: <span id="procNum"></span>
</p>

<div class="progress">
  <div class="progress-bar" role="progressbar" id="progress-bar-movie" 
       aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>

Ответ 2

Это связано с тем, как бутстрап оживляет изменения состояния индикатора выполнения. Если интервал тайм-аута меньше времени анимации, он будет чередовать перерисовку.

Попробуйте добавить это в свой индикатор выполнения CSS:

-webkit-transition: none;
transition: none;

Проверьте мою скрипку

Ответ 3

Еще одна работа вокруг (со ссылкой на мой предыдущий ответ):

Если вы должны сохранить анимацию, вы можете использовать консервативную задержку интервала, например, 100 миллисекунд. Задержка, которая не должна быть заметной для пользователя.

Ответ 4

Если вам действительно нужно, чтобы задержка была равна нулю для вычислений, я бы разделил вычисления и настройку значения индикатора выполнения так, чтобы вы вычисляли значение в одном setInterval, а затем запускали отдельный setInterval который обновляет строку каждые 100 мс до этого значения.

Таким образом, ваши расчеты обновлены, и ваш пользовательский интерфейс имеет время, необходимое для его обновления.

Если вы хотите, чтобы они оба были в одном методе, я думаю, вам нужно добавить минимальную задержку в 100 мс.

Пример: https://jsfiddle.net/dk7g51g4/3/

JavaScript:

var _ValueToSet = 0;
$(document).ready(function () {

    // SET VALUE EXTREMELY FAST (your current code)
     setInterval(function () {
        _ValueToSet = Math.round(Math.random() * 100); // get value we are going to set
    }
    , 0); // run as fast as possible

    // RUN UI UPDATE AT 100MS (separate thread for ui updates).
    setInterval(function () {
        setRandom()
    }
    , 100); // give ui 100ms to do its thing
});

function setRandom() {
    var elem = $('.progress-bar'); // what is our target progress bar

    // set both style width and aria-valuenow
    elem.css('width', _ValueToSet + '%');
    elem.attr('aria-valuenow', _ValueToSet);
}

HTML:

<div class="progress progress-striped active">
    <div class="progress-bar" 
        style="width:0%" 
        role="progressbar" 
        aria-valuenow="0" 
        aria-valuemin="30" 
        aria-valuemax="100">
    </div>
</div>

Ответ 5

Это, вероятно, проблема с перерисованием. Поскольку для задержки установлено значение 0, изменения CSS не отображаются до последнего обновления.

Самый простой способ заставить перерисовать - прочитать высоту элементов:

$("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer);
$("div[role='progressbar']").height();

Ответ 6

Текст и индикатор выполнения изменяются динамически, но с delay === 0 он очень быстро: (http://jsfiddle.net/sergdenisov/mh4o1wxz/1/):

HTML:

<div class="text">Text</div>
<div class="progress">
    <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;">
    </div>
</div>

JavaScript:

var delay = 0;
var percent = 0;

var iID = setInterval(function() {
    percent += 10;
    $('.text').text('Text ' + percent + '/100');
    $('.progress-bar').css('width', percent + '%').attr('aria-valuenow', percent);    
    if (percent === 100) {
        clearInterval(iID);
    }
}, delay);