0

I am sorry for the general question, but I would really like this one to be handled.

I am used to programming languages live Java or PHP, where program executes line by line, but sometimes I use javascript when it has good libraries.

The asynchronity stuff drives me nuts.

document.body.innerHTML = "";
for(var i=0;i<3;i++){
    document.body.innerHTML+="Hi! ";
    alert();
}

I expect this piece of code to work like this:

  1. Delete the whole content of the "body" tag.
  2. Print "Hi! "
  3. Invoke alert.
  4. Print "Hi! ".
  5. Invoke alert
  6. Print "Hi! ".
  7. Invoke alert.

In reality it works like this:

  1. Invoke alert
  2. Invoke alert
  3. Invoke alert
  4. Delete the whole content of the "body tag".
  5. Print "Hi! ".
  6. Print "Hi! ".
  7. Print "Hi! ".

How to make javascript code behave like a normal program?

Thank you!

UPDATE:

The first duplicate suggestion is not a duplicate at all. It has completely different code (I don't even use setTimeout), different task and different explaination. Even if the answer to my question is hidden there somewhere (in the comment number 56 or something like that), it is so unclear, that should not be taken as a duplicate.

The selected solution in the second duplicate suggestion simply does not work:

function b(){
    document.body.innerHTML = ""; for(var i=0;i<3;i++){ 
        document.body.innerHTML+="Hi! ";
        alert();
    }
}
function c(){
    setTimeout(b, 1);
};
c();

So NO, NEITHER of these links are duplicates.

Jaroslav Tavgen
  • 312
  • 1
  • 9
  • https://stackoverflow.com/questions/27323772/javascript-function-and-ui-updates – mplungjan Dec 20 '17 at 11:58
  • I didn't understand anything from that thread. Some paiting, some CSS, some browser control. In my opinion, it would be much better to answer my direct and very clearly stated question (which, I think, is relevant for lots of people), than to refer to very unclear and very specific question. – Jaroslav Tavgen Dec 20 '17 at 12:01
  • The browser has only a single thread, and that what you call "asynchronity" is actual synchronity. The only thread is reserved by JS until all the code has been executed, and then the time for rendering will become. That's "normal" in JS. – Teemu Dec 20 '17 at 12:02
  • You have THREE duplicate links. reload your browser: This one is VERY similar to yours https://stackoverflow.com/questions/37953871/how-to-force-repaint-in-js – mplungjan Dec 20 '17 at 12:02
  • Also never use alert if you want your script to continue running. alert, prompt and confirm are BLOCKING methods – mplungjan Dec 20 '17 at 12:07
  • function b(){document.body.innerHTML = ""; for(var i=0;i<3;i++){ document.body.innerHTML+="Hi! "; alert(); }};function c(){setTimeout(b, 1);};c(); - Absolutely same result – Jaroslav Tavgen Dec 20 '17 at 12:12
  • `function b() { document.getElementById("x").innerHTML += "Hi! "; console.log("hi") }; function c() { document.getElementById("x").innerHTML = ""; for (var i = 0; i < 3; i++) { setTimeout(b, i*1000); } };` – mplungjan Dec 20 '17 at 12:23
  • @mplungjan It I change console.log to alert, it executes BEFORE adding "Hi!" to the container – Jaroslav Tavgen Dec 20 '17 at 12:35
  • How about taking some time, and read what really was written here in the comments, and in the dups, then apply the learned stuff to your code, and you finally have what you need. What comes to console, it really is asynchronous, and you can't change the behavior. The loggings are happening in some time range, no matter what and when you're going to log. Sometimes you even will get wrong information logged because of the timing. – Teemu Dec 20 '17 at 12:56
  • The dups do not have what I need. The rendering and animation has NOTHING to do with my question. My question is: how to make sure in javascript, that A comes after B? In all other programming languages I just put A below B. In javascript it doesn't work. But what will work? – Jaroslav Tavgen Dec 20 '17 at 13:00
  • 1
    A actually comes after B. See https://jsfiddle.net/ta15gxy6/ . What doesn't happen is an update of the view, which is not part of JavaScript itself. So what you need is to give the browser time to update the view before you ask something from the view. In most cases, you just need the DOM and not the view so it doesn't matter. To give the browser enough time for the view to update you could use an overly complex example like https://jsfiddle.net/05bej59L/ . TLDR; if you correctly use JS, it doesn't really matter. – René Dec 20 '17 at 18:23

1 Answers1

0

You can try something like this:

document.body.innerHTML = "";

function update() {
  document.body.innerHTML += "Hi! ";
  alert();
}
for (var i = 0; i < 3; i++) {
  setTimeout(update, 0);
}

Edit: A bit ugly, but this should do the job

let i = 0;
document.body.innerHTML = "";
requestAnimationFrame(function next() {
  document.body.innerHTML += "Hi! ";
  i++;
  setTimeout(function() {
    alert();
    if (i < 3) {
      requestAnimationFrame(next);
    }
  }, 0)
})
mplungjan
  • 169,008
  • 28
  • 173
  • 236
blaz pecnik
  • 185
  • 4
  • 3
    Which is funny because it's an asynchronous solution to an asynchronous problem. – René Dec 20 '17 at 12:02
  • Does not work. It FIRST executes alert, and THEN prints "Hi! ". – Jaroslav Tavgen Dec 20 '17 at 12:05
  • It could work when you change it to have the alert inside a timeout with the alert and update in it(but don't use a loop but a more functional programming). But using this will not block execution of other code which might rely on the outcome of this code... so it's a semi-solution for a very specific case. In general you should just embrace the async, event driven, system and learn to work with it. – René Dec 20 '17 at 12:13
  • To embrace what? Look, how many answers to a very simple question, AND STILL NO SOLUTION THAT WORKS. – Jaroslav Tavgen Dec 20 '17 at 12:18
  • The second solution (starting with "let...") does not work as well. – Jaroslav Tavgen Dec 20 '17 at 12:19
  • Hmmm... the second solution works for me :/ Can you specify how exactly it dosn't work? – blaz pecnik Dec 20 '17 at 12:21
  • 1
    @blazpecnik PLEASE use the snippet editor or indent 4 spaces instead of using the `` tag – mplungjan Dec 20 '17 at 12:24
  • @blazpecnik, here is what I do. 1. Open new page in Google Chrome. 2. Press F12. 3. Copy-paste the text to the console. 4. Press Enter. 5. Get 3 alerts in a row. 6. Get "Hi! Hi! Hi! " on the screen. – Jaroslav Tavgen Dec 20 '17 at 12:25
  • @mplungjan thanks, will do! Sorry, im still new and learning how stuff works :) – blaz pecnik Dec 20 '17 at 12:26
  • @JaroslavTavgen 2nd solutions works for me as well. Just to be sure you could use requestIdleCallback. And really, it is a simple question but it only needs to be asked if your code-flow is not built to work with JavaScript. Javascript is perfectly capable of waiting to show an alert once a specific condition is met, like a user interaction or something printed to the screen. – René Dec 20 '17 at 12:50