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>