Ответ 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>