Javascript не печатает текст сразу
Я написал этот код, который должен сказать "привет", когда я нажимаю кнопку "привет":
<!DOCTYPE html>
<html>
<head>
<script>
var someLargeNumber = 5000000000;
function hello() {
document.getElementById('hi').innerHTML = "hi";
for(var i = 0; i < someLargeNumber; i++) {}
}
</script>
</head>
<body>
<p id="hi"></p>
<input type="button" value="hello" onclick="hello();">
</body>
</html>
Он говорит привет, но только после завершения цикла for
. Почему это происходит и как я могу это исправить?
Спасибо
Ответы
Ответ 1
Почему это происходит...
Поскольку браузеры запускают JavaScript в основном потоке пользовательского интерфейса, они используют для обновления страницы по разным причинам. Поэтому, хотя вы указали текст "hi", он не отображается, пока код JavaScript, выполняющийся в ответ на событие, не завершится.
... и как я могу это исправить?
Возвратитесь к браузеру после добавления текста, прежде чем делать то, что вы имитируете с помощью этого цикла. setTimeout
с задержкой 0
подходит для многих случаев:
var someLargeNumber = 5000000000;
function hello() {
document.getElementById('hi').innerHTML = "hi";
setTimeout(function() {
for(var i = 0; i < someLargeNumber; i++) {}
}, 0);
}
Механизм JavaScript работает в основном в цикле с очередью задач (спецификация называет их "заданиями" ). Он забирает задание из очереди, запускает его до завершения и затем ищет следующую работу. Браузеры (обычно) обновляют пользовательский интерфейс, когда двигатель находится между заданиями. Когда происходит событие, задание помещается в очередь для вызова обработчика события. Вышеприведенное просто перемещает цикл в новое задание, он ставит очередь через setTimeout
, поэтому браузер имеет возможность после задания события и перед заданием setTimeout
обновлять пользовательский интерфейс.
Ответ 2
Как уже было сказано, браузер имеет один поток пользовательского интерфейса.
Другой вариант - использовать Web Worker
(если вы не выполняете никаких манипуляций с DOM в рабочем потоке), что позволяет запускать операции в другом потоке.
Добавьте еще один файл js (скажем, worker.js)
var someLargeNumber = 5000000000;
onmessage = function(e) {
console.log('Message received from main script');
for(var i = 0; i < someLargeNumber; i++) {}
console.log('Posting message back to main script');
postMessage('done');
}
Вернуться в основной файл
<head>
<script>
var myWorker = new Worker("worker.js");
function hello() {
document.getElementById('hi').innerHTML = "hi";
myWorker.postMessage('test');
console.log('Message posted to worker');
}
myWorker.onmessage = function(e) {
result.textContent = e.data;
console.log('Worker thread is complete');
}
</script>