0

The issue is the following: I want to modify a h1 (id="waiting") and then execute a function that takes several seconds to complete (solve).

function solveWrapper(table) {
        document.getElementById("waiting").innerHTML = "Wait please, Nurikabe is being solved...";
        alert("alert");
        var currentState = new State(table);
        solve(table, currentState);
    }

With this code I get the alert before the solve function is called, but the h1 tag is modified only after that function execution is finished. Does anyone know how to fix this? This is the button that calls solveWrapper:

<button onclick="solveWrapper(grid);">Solve</button>

Here is the whole code: https://github.com/jackowski626/projects/blob/master/Nurikabe_SJ_Solver.html

  • 2
    Put the call to `solve()` in a timeout handler – Pointy Oct 16 '19 at 19:35
  • @Pointy I placed it in a 5 sec timeout and it does not change anything –  Oct 16 '19 at 19:37
  • can you add the code you use to call the function (solveWrapper)? Maybe there another function/code that is making the change, in order words, the element is being updated correctly – Leonidas Menendez Oct 16 '19 at 19:39
  • You could do it with a **callback** function, or modify your code to return a **Promise**. That ought to solve it. (Or **async await** syntax.) – muka.gergely Oct 16 '19 at 19:40
  • @LeonidasMenendez it is called via a html button. That might be the issue –  Oct 16 '19 at 19:41
  • Possible duplicate of [Update webpage to show progress while javascript is running in in a loop](https://stackoverflow.com/questions/32299326/update-webpage-to-show-progress-while-javascript-is-running-in-in-a-loop) – Heretic Monkey Oct 16 '19 at 19:54
  • Or [How to avoid freezing the browser when doing long-running computations in Javascript](https://stackoverflow.com/q/13546493/215552) – Heretic Monkey Oct 16 '19 at 19:56

2 Answers2

1

Put the call to solve() in a timeout handler:

function solveWrapper(table) {
    document.getElementById("waiting").innerHTML = "Wait please, Nurikabe is being solved...";
    var currentState = new State(table);
    setTimeout(function() {
      solve(table, currentState);
    }, 10);
}

Browsers defer updating the view until event loops finish unless they have no choice.

Pointy
  • 405,095
  • 59
  • 585
  • 614
0

I'd say give this a go:

function solveWrapper(table) {
  window.requestAnimationFrame(
    document.getElementById("waiting").innerHTML = "Wait please, Nurikabe is being solved..."
  );
  alert("alert");
  var currentState = new State(table);
  solve(table, currentState);
}

The idea is that requestAnimationFrame should cause a browser repaint and update what's rendered on the screen for you. I think the issue is that you're calling a change to the innerHTML but it's not being reflected in the browser until it's ready to do it, which is after it runs your solve function.

https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

Brett East
  • 4,022
  • 2
  • 20
  • 31
  • `requestAnimationFrame` expects its parameter to be a function. Did you mean to wrap the third line in a function expression? – Jordan Running Oct 16 '19 at 20:43
  • yeah, apologies, `window.requestAnimationFrame(() => { document.getElementById("waiting").innerHTML = "Wait please, Nurikabe is being solved..."} );` Although now I'm wondering if you could just wrap it in an immediately invoked function without the `requestAnimationFrame` – Brett East Oct 16 '19 at 20:46