skip to Main Content

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, the calculation_x(arr, count) function does not work correctly, and a custom timeout(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


  1. 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.

    function timeout(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    async function calculation_x(arr, count) {
      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 (let 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}`);
        await timeout(1000);
      }
      await 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>
    Login or Signup to reply.
  2. Your timeout method is very computationally expensive, and interrupts the rendering of your table. You are right that you’ll have to use setTimeout or setInterval, 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 recursive update_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.

    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;
    
      function update_table() {
        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}`);
        i++;
        if (i === count) {
          setTimeout(function() {
            let result = `<tr><td colspan="2">Результат: ${sum}</td></tr>`;
            document.getElementById(`result`).innerHTML += result;
            console.log(`Сумма положительных элементов: ${sum}`);
          }, 1000);
        } else {
          setTimeout(update_table, 1000);
        }
      }
      update_table();
    }
    
    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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search