0

I'm writing a short program to learn about Promises in JavaScript.

The goal of the program is to print a list of numbers (decreasing from 5 to 0) onto a HTML page, with a delay of 0.5s between each number. After the 0 is printed, a confirm box pops up and allows the user to print the same numbers again or stop.

Currently, the code below is mostly working but it acts very strangely during the first and second iteration of the inner loop (in the countdown() function) - between printing the first 5 and 4.

I've debugged it a lot in chrome dev to try to figure out what's happening, so I've included a step-by-step guide as to what the program is actually doing (or appears to be doing) beneath the code section, with the strange behaviours in bold.

This is an unmarked assignment for university and I managed to stump my professor so any help is much appreciated. Thanks in advance!!

// wait time for setTimeout
var wait = 500;

function timer(ms) {
  return new Promise((res) => {
    setTimeout(res, ms);
  });
}

async function countdown() {
  for (let i = 5; i >= 0; i--) {
    document.write("<br>");
    document.write(i);
    console.log(i);
    await timer(wait).then();
  }
  var c = confirm("Do you want to go again?");
  document.write("<br>User Confirm:");
  document.write(c);
  console.log(c);
  return c;
}



async function repeatRun() {
  var prom = new Promise(async(res, rej) => {
    r = await countdown();
    if (r) {
      res();
    } else {
      rej();
    }
  });
  prom.then(
    data => {
      document.write("<br>RERUN");
      console.log("RERUN");
      repeatRun();
    },
    error => {
      document.write("<br>ENDED");
      console.log("ENDED");
    }
  );
}

repeatRun();
<!DOCTYPE html>
<html>

<head>
  <title>Countdown</title>
</head>

<body>
  <h1>Countdown</h1>
  <p>Internet Applications Ex1.</p>
</body>

</html>

This is what my program is doing step by step:

  1. displays HTML page title etc

  2. enters script tag

  3. enters repeatRun()

  4. creates Promise variable prom and enters countdown()

  5. first iteration of for loop (ie i=5)

    5.1. prints <br> and 5 using document.write(), both are appended to the HTML body

    5.2. enters timer()

    5.3. returns new Promise

    5.4. this promise returns to prom.then() inside repeatRun() instead of to await timer() call like i expected

    I have tried this with and without .then() afterwards and it does the same thing [this happens in one step on the Chrome debugger]

  6. exits the script tag

  7. re-enters the script tag, but not from the beginning: it returns to the for loop and decreases i

    current HTML file:

    <html>
    <head>
    <title>Countdown</title>
    </head>
    <body>
    <h1>Countdown</h1>
    <p>Internet Applications Ex1.</p>
    <script>...</scri pt>
    <br>
    "5"
    </body>
    </html>
    
  8. the next document.write() call, instead of appending <br> to the HTML body, replaces the old HTML body with <br>, the head tag is also erased

  9. the next document.write() appends i (now 4) to the new HTML file current HTML file:

    <html>
    <head></head>
    <body>
    <br>
    "4"
    </body>
    

this is where the program starts to behave as expected 10. enters the timer() function and then returns to countdown() afterwards 11. loops as expected until i=0

11.1. `document.write()` appends to HTML body instead of rewriting 

11.2. `timer()` function is called and returns to `countdown()` function afterwards
  1. after this loop, the confirm window pops up : I click "ok" and true is stored in c, printed using document.write(), and returned and stored in r
  2. since r=true, if succeeds and res() is called
  3. enters the prom.then() and then data => and document.write appends "<br>RERUN" to HTML body correctly
  4. the repeatRun() function is called recursively
  5. creates new promise var and calls countdown()
  6. this time, the for loop happens as expected (ie in step 11) from i=5 to i=0
  7. after the loop, I click "cancel" in the confirm window, c is set to false, printed, and returned and stored in r
  8. since r=false, if fails and rej() is called
  9. enters the prom.then() and then error => and document.write appends "<br>ENDED" to HTML body correctly
  10. exits script tag
Randy Casburn
  • 11,404
  • 1
  • 12
  • 26
sastaffo
  • 1
  • 2
  • Once you start using `document.write`, all bets are off. You've basically given free reign to JavaScript to do whatever it wants to the page. If you want to solve the problem, don't use `document.write`. – Heretic Monkey Oct 22 '20 at 17:51
  • https://stackoverflow.com/questions/802854/why-is-document-write-considered-a-bad-practice – epascarello Oct 22 '20 at 18:00

1 Answers1

0

MDN documentation for documentation.write() says

Note: Because document.write() writes to the document stream, calling document.write() on a closed (loaded) document automatically calls document.open(), which will clear the document.

So for the first time(first iteration) the document is somehow not completely loaded which means it is open, so document.write() just works as usual. But after the first iteration the document somehow completes loading so the document is now closed, now when it calls document.write() it have to open the document again since it is closed, which clears up the whole document (5 gets replaced with 4) and for the rest of the iterations the document stays open so it just works as usual.

You should not use document.write(), use any other method to change the content of the page.

Sarsa Murmu
  • 309
  • 3
  • 9