Это классическая c проблема, возникающая в результате длительной работы функции, которая периодически не останавливается для передачи управления обратно в событие браузера L oop, где браузер может выполнять другие задачи, такие как рисование элементы:
Недостатком этой модели является то, что если сообщение занимает слишком много времени, веб-приложение не может обрабатывать взаимодействия с пользователем, такие как щелчок или прокрутка. Браузер смягчает это с помощью диалога «скрипт слишком долго запускается». Хорошая практика заключается в том, чтобы сделать обработку сообщений короткой и по возможности разделить одно сообщение на несколько сообщений.
Модель параллелизма и событие l oop - MDN
Если в браузере нет «передышки», потому что ваш JS l oop имеет контроль, браузер не может нарисовать индикатор выполнения.
Чтобы это исправить, вы вам нужно запустить l oop порциями, то есть «разрезать одно сообщение на несколько сообщений», как рекомендует MDN. Чтобы выполнить это sh, вам нужно будет использовать что-то асинхронное, например тайм-аут, чтобы браузер запустил следующую итерацию не "сразу", а "как только вы будете готовы". Это позволяет браузеру выполнять другие важные действия до того, как ваша функция будет продолжена (например, обрабатывать прокрутки и щелчки, а также рисовать такие элементы, как индикатор выполнения).
Решение
Следующее решение не работает l oop, возвращая управление браузеру с setTimeout(fn, 0)
каждые x
итераций.
Это полезно, если выполняемая вами задача связана с DOM или по какой-либо другой причине не может быть запущена в веб-работник. В противном случае решение @ blex для веб-рабочих , вероятно, лучше, поскольку любые долгосрочные задачи, которые можно запускать в фоновых потоках, должны быть из соображений производительности.
const MAX = 500000;
let currentIteration = 0;
function doWork(){
while (currentIteration < MAX) {
// Do your actual work here, before the increment
currentIteration++;
if (currentIteration % 5000 === 0) {
console.log(currentIteration);
updateBar(currentIteration);
setTimeout(doWork, 0);
return;
}
}
alert('count ended');
}
function startWork() {
alert('start count :'+ MAX);
doWork();
}
function updateBar(idx) {
var bar = document.getElementById('progress');
bar.style.width = Math.floor(100 * idx / MAX) + '%';
}
body {padding: 50px;}
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css" rel="stylesheet"/>
<button onclick="startWork()">Start counting</button>
<div class="progress">
<div class="bar" id="progress"></div>
</div>