Я знаю, что это может быть глупый вопрос, но он сводит меня с ума. Я пытаюсь изменить innerHTML элемента DOM, но он не меняется до конца выполнения функции. Например:
function test(){
let testEl = document.getElementById('testEl')
for (let i = 0; i < 5; i++)
{
testEl.innerHTML = 'Count: ' + i;
alert(i);
}
}
Даже если я поставил алерт в цикле, текст элемента не изменится до конца выполнения функции. Как можно применить изменение мгновенно (например, я имею в виду во время цикла)?
Потому что поток блокируется. Хотя в данном конкретном случае я не вижу, как это будет иметь значение. Код завершит 5 циклов быстрее, чем человеческий глаз сможет даже распознать 5 отличий. (Если бы дисплей мог даже отчетливо отображать все 5 из них так быстро.)
@David В каждом повторении есть предупреждение (), которое останавливает выполнение. Таким образом, пользователь сможет увидеть изменения. Дело в том, что элемент DOM не меняется. Если вы добавите console.info('Count: ' + i), вы сможете видеть числа в консоли (одно за другим после предупреждающего сообщения), но все равно не в элементе DOM.
Вам нужно немного больше узнать об одно- и многопоточной обработке. JavaScript — это язык однопоточной обработки. Но он выполняется в многопоточном клиенте (браузере). JavaScript может запросить alert, но это браузер просит операционную систему сделать это в отдельном потоке, и, поскольку оповещение является «модальным» диалогом, он блокирует выполнение всех других браузеров, поэтому вы не увидите обновление страницы во время оповещение присутствует.
На самом деле предупреждение просто для примера. Что я делаю, так это сначала меняю DOM (например, помещаю текст «загрузка»), затем вызываю php-файл для получения некоторых данных, а затем снова меняю DOM на «Готово». Единственное, что я вижу, это «Готово» в конце, даже если обработка занимает 4-5 секунд. Я предполагаю, что это связано с sync/asych, поэтому ваши ответы полезны!
Просто нет гарантии, что браузер сможет или будет обновлять пользовательский интерфейс между предупреждениями таким образом. Фаерфокс умеет, хром нет. Однако вы можете запрограммировать его так, чтобы вы могли обновлять элемент между предупреждениями для всех браузеров.
Это потому, что процесс идет так быстро, это делается почти сразу. Ответ Маджеда ниже - это правильный способ «замедлить процесс», чтобы вы могли видеть происходящие изменения.
@ СкоттМаркус Я так не думаю. Я установил таймер каждые 0,5 секунды (после загрузки страницы). У меня есть кнопка, которая запускает выполнение скрипта. Таймер зависает на некоторое время, когда скрипт выполняется. Я думаю, что это связано с открытием XMLHttpRequest, которое я делаю. Если я использую консоль для регистрации того, что хочу, она отлично работает, но это не относится к элементу DOM.
Мне жаль, что вы так не думаете, но вы ошибаетесь. Я занимаюсь этим и учу этому с тех пор, как был изобретен JavaScript. Если ваш таймер зависает, это потому, что вы неправильно его реализуете. XMLHttpRequest по умолчанию является асинхронным, поэтому он не блокирует ваш код JavaScript. Как я уже сказал, вам нужно узнать, как работает асинхронная обработка в однопоточном JavaScript. Этот однопоток всегда имеет приоритет над любым асинхронным кодом, который он мог породить (например, таймеры). Таким образом, нельзя рассчитывать на то, что таймеры будут запускаться точно в указанное время.
Я очень рад, что вы преподаете JS с 1995 года! XMLHttpRequest по умолчанию является асинхронным, но это изменится, если вы установите для асинхронности значение false (это то, что я сделал). Итак, я должен установить для async значение true и управлять продолжением скрипта из функции .onload запроса. Вот и все.
Установка async на false сводит на нет всю цель XHR, поэтому вы можете просто выполнить встроенную функцию — вот и все. Вы не делаете то, что пытаетесь сделать правильно, и мы пытаемся рассказать вам, как это сделать, но вы, похоже, хотите просто поспорить.
@ScottMarcus «Это потому, что процесс идет так быстро, что он выполняется почти сразу. Ответ Маджеда ниже — это правильный способ «замедлить процесс», чтобы вы могли видеть происходящие изменения». Это был ваш ответ, и я отвечаю: «Я так не думаю», потому что это не было проблемой.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете обновлять число каждый период времени, используя setInterval:
function test(){
let testEl = document.getElementById('testEl');
let i = 0;
const interval = setInterval(function(){
testEl.innerHTML = `Count: ${i++}`;
if (i === 5)
clearInterval(interval);
}, 1000);
}
test();<p id = "testEl"></p>Решение Interval не помогает в моей ситуации. В вашем первом решении просто поместите предупреждение в цикл, чтобы увидеть, что именно я имею в виду: `function test(){ let testEl = document.getElementById('testEl') for (let i = 0; i < 5; i++) { testEl .innerHTML += Count: ${i}<br>; предупреждение('ПАУЗА'); // testEL не изменился и не изменится до конца функции } } test(); `
@MyWherany the for-loop работает быстро, и это нормально видеть только конечный результат. Вот почему я предложил добавить содержимое, чтобы показать все итерации, или использовать интервал, чтобы показать медленное изменение переменной.
JavaScript работает в однопоточной среде. Это означает, что в любой момент времени может выполняться только один контекст выполнения. Асинхронный код выполняется за пределами среды выполнения JavaScript (в данном случае за счет собственной обработки браузера), и только когда поток JavaScript бездействует, могут быть выполнены результаты асинхронного запроса (т. е. обратные вызовы).
Ниже приведен пример, который обновляет элемент DOM примерно каждую секунду, создавая часы. Однако, если вы нажмете кнопку, он попросит браузер отобразить alert, который обрабатывается вне среды выполнения JavaScript и является блокирующим элементом пользовательского интерфейса, поэтому часы остановятся. Как только вы очистите предупреждение, вы увидите, что временной скачок будет примерно текущим.
Как вы увидите, асинхронный вызов API window.setInterval() позволяет функции выполняться многократно, время от времени и, следовательно, не непрерывно. Это заменяет необходимость в цикле, который выполняется полностью каждый раз, когда к нему обращаются. Из-за этого вы можете видеть обновления на веб-странице вместо последнего значения вашего цикла.
Подробности смотрите в комментариях:
const clock = document.querySelector("span");
// setInterval is not JavaScript. It's a call to a browser
// API asking the JS runtime to run the supplied function every
// 900 milliseconds, but that's just a request. After 900
// milliseconds, the browser will place the function on the
// JavaScript event queue and only when the JavaScript thread
// is idle will anything on the queue be executed. This is why
// the 900 milliseconds is not a guarantee - - it's just the
// minimum amount of time you'll have to wait for the function
// to run, but it could be longer if what's already running
// on the JavaScript thread takes longer than 900 milliseconds
// to complete.
window.setInterval(function(){
// Update the DOM
clock.textContent = new Date().toLocaleTimeString();
}, 900);
document.querySelector("button").addEventListener("click", function(){
// An alert is also not JavaScript, but another browser API that is executed
// by the browser, not JavaScript. However, it is a blocking (modal) UI element.
// The rest of the browser interface (including the web page) cannot update
// while the alert is present. As soon as the alert is cleared, the UI will update.
window.alert("I'm a UI blocking construct rendered by the browser, not JavaScript");
});<div>Current time is: <span></span></div>
<button>Click for alert</button>Другой способ добиться этого - использовать async - Promise вот так
async function test() {
let testEl = document.getElementById('testEl')
for (let i = 0; i < 5; ++i) {
testEl.innerHTML = 'Count: ' + i;
await new Promise((resolve, _) => {
setTimeout(function() {
resolve("");
}, 1000 /* your preferred delay here */);
});
}
}
Вам нужно сделать анимацию с таймаутами