#javascript #html #dom
#javascript #HTML #dom
Вопрос:
Я знаю, что это может быть глупый вопрос, но он сводит меня с ума. Я пытаюсь изменить innerHTML элемента DOM, но он не меняется до конца выполнения функции. Например:
function test(){
let testEl = document.getElementById('testEl')
for (let i = 0; i < 5; i )
{
testEl.innerHTML = 'Count: ' i;
alert(i);
}
}
Даже если я поместил предупреждение в цикл, текст элемента не изменится до конца выполнения функции. Как изменение может быть применено мгновенно (например, я имею в виду во время цикла)?
Комментарии:
1. @David При каждом повторении появляется alert(), который останавливает выполнение. Таким образом, пользователь сможет увидеть изменения. Дело в том, что элемент DOM не меняется. Если вы добавите console.log(‘Count: ‘ i), вы сможете видеть числа в консоли (одно за другим после предупреждающего сообщения), но все равно не в элементе DOM.
2. youtube.com/watch?v=4xsvn6VUTwQ
3. Вам нужно узнать немного больше об однопоточной и многопоточной обработке. JavaScript — это однопоточный язык обработки. Но он выполняется в многопоточном клиенте (браузере). JavaScript может запрашивать
alert
, но именно браузер запрашивает операционную систему сделать это в отдельном потоке, а поскольку оповещение является «модальным» диалогом, оно блокирует все остальные выполнения браузера, поэтому вы не увидите обновление страницы, пока присутствует оповещение.4. Мне жаль, что вы так не думаете, но вы ошибаетесь. Я делаю и преподаю это с тех пор, как был изобретен JavaScript. Если ваш таймер зависает, это потому, что вы неправильно его реализуете. XMLHttpRequest по умолчанию является асинхронным, поэтому он не будет блокировать ваш код JavaScript. Как я уже сказал, вам нужно узнать, как работает асинхронная обработка в JavaScript, который является однопоточным. Этот однопоточный код всегда имеет приоритет над любым асинхронным кодом, который он мог породить (например, таймеры). Таким образом, нельзя рассчитывать, что таймеры будут выполняться точно в указанное время.
5. Установка async на
false
поражение всей цели XHR, поэтому вы можете просто выполнить встроенную функцию — вот и все. Вы не делаете то, что пытаетесь сделать правильно, и мы пытаемся рассказать вам, как это сделать, но вы, похоже, хотите просто поспорить.
Ответ №1:
Вы можете обновлять номер каждый период времени, используя 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>
Комментарии:
1. Интервальное решение не помогает в моей ситуации. В вашем первом решении просто поместите оповещение в цикл, чтобы увидеть, что именно я имею в виду: ` function test(){ let testEl = document.getElementById(‘testEl’) for (let i = 0; i < 5; i ) { testEl.innerHTML =
Count: ${i}<br>
; alert(‘ПАУЗА’); // testEL не изменился и не изменится до конца функции } } test(); `2. @MyWherany
for-loop
выполняется быстро, и нормально видеть только конечный результат. Вот почему я предложил добавить содержимое, чтобы показать все итерации, или использовать интервал, чтобы показать медленное изменение переменной.
Ответ №2:
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>
Ответ №3:
Другой способ добиться этого — использовать 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 */);
});
}
}