The task of the script:
- to create an array of numbers, the dimension of which is determined by the data in the form, the
send_n()
function is responsible for this; - after that, display a table of two columns on the page: an array element and the sum of the positive elements of the array at the moment;
- at the end of the table, output the result in one row of the table into 2 columns: the final sum of positive elements;
- at the same time, each row of the table should appear with a delay of 1 second, I have the
timeout(ms)
function responsible for this, most likely it is not the best solution, but as I understood,setTimeout(() => { do sth }, ms)
is an asynchronous function, so in my in this case, using it, thecalculation_x(arr, count)
function does not work correctly, and a customtimeout(ms)
function has appeared.
The problem is that when the loop is triggered, the result is output to the console as needed, but the table is output only at the execution stage of this line:
document.getElementById(`result`).innerHTML += result;
after completing the cycle.
I attach Code:
function timeout(ms) {
let date = new Date();
while ((new Date()) - date <= ms) {
// w/o do
}
}
function calculation_x(arr, count) {
let i = 0;
let sum = 0;
let table = String(`<table border="1px"><thead><tr><td>Элемент массива</td><td>Сумма положительных элементов массива</td></tr></thead><tbody id="result"></tbody></table>`);
document.getElementById(`table-div`).innerHTML = table;
for (i = 0; i < count; i++) {
if (arr[i] > 0) {
sum += arr[i];
}
table = `<tr><td>X[${i}] = ${arr[i]}</td><td>${sum}</td></tr>`;
document.getElementById(`result`).innerHTML += table;
console.log(`X[${i}] = ${arr[i]} | ${sum}`);
timeout(1000);
}
timeout(1000);
let result = `<tr><td colspan="2">Результат: ${sum}</td></tr>`;
document.getElementById(`result`).innerHTML += result;
console.log(`Сумма положительных элементов: ${sum}`);
}
function send_n() {
let i = 0;
let n = Number(document.getElementById(`n`).value);
let numbers = new Array(n);
for (i = 0; i < n; i++) {
numbers[i] = Number(Math.floor(Math.random() * 200) - 100);
}
calculation_x(numbers, n);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form>
<input type="text" id="n" placeholder="Количество элементов массива">
<input type="button" value="Принять" onclick="send_n()">
</form>
<div id="table-div"></div>
<script src="/scripts.js"></script>
</body>
</html>
I tried using setTimeout();
and setInterval();
, but this did not give the desired result for the reasons described above.
2
Answers
DOM changes aren’t rendered until JavaScript is idle and returns to the main event loop. You can’t use a busy-wait function to see intermediate changes.
You can use a Promise to implement a
timeout()
function that returns to the event loop and allows the incremental changes to render.Your
timeout
method is very computationally expensive, and interrupts the rendering of your table. You are right that you’ll have to usesetTimeout
orsetInterval
, but using these functions requires you to think in an asynchronous way.Here’s a potentially modificaton to your code, with the
timeout
function removed. Here we replace the body of the for loop with a recursiveupdate_table
function that will either continue to update the table, or display the final sum depending on how many rows have been processed so far.