0

I want to set the cursor style to 'wait' while a lengthy javascript function is running, and then reset back to normal afterwards.

I thought this might be enough:

document.body.style.cursor = 'wait';
// long scripting here
document.body.style.cursor = 'auto';

However .. if I move the cursor to point at (e.g.) an <input> then the cursor changes to the appropriate type e.g. 'text'. (Tested via individual commands in the console).

I did find this similar question, which sets up a css rule of
html.wait, html.wait * { cursor: wait !important; }
and uses that via this js:

document.querySelector("html").classList.add("wait");
// long scripting here
document.querySelector("html").classList.remove("wait");

.. but .. it doesn't seem to kick in while the script is running.

Erics
  • 803
  • 9
  • 23
  • 1
    https://jsfiddle.net/gwmc1b65/ it seems to be working here.. – Rayon Oct 08 '21 at 04:36
  • Works ok here too with a script toggling the class ~ https://jsfiddle.net/12jLm5w6/1/ – Phil Oct 08 '21 at 04:43
  • @phil Ah, you've separated the add/remove class script steps with setTimeout/await stuff. Would that still work if instead it was doing actual busy work? – Erics Oct 08 '21 at 05:48
  • I'm not sure. Perhaps try replacing it with a massive `for` loop (sorry, I don't really know how to simulate synchronous busy work in JS) – Phil Oct 08 '21 at 06:03
  • 1
    So the problem is solved? If no, then please provide an example of "long scripting here", possible the issue is there – Andrei Vorsa Oct 08 '21 at 21:01
  • @AndreiVorsa Kinda solved, but in a "optimised the code such that the wait time went from tens of seconds and growing to be only a consistent 300ms wait each time" way. Turns out, adding 35 lines of text to a textarea in a loop of a thousand iterations will take 3500ms. And another 4800ms to add a further 1000 × 35 lines, then 8200ms for the next 1000 iterations (etc). So .. no, problem as posted here not solved, only averted =( – Erics Oct 18 '21 at 04:54

1 Answers1

0

Put an idle delay where JS can release the CPU back to the browser so it gets a chance to do a repaint (or whatever it's called).

const DELAY_FOR_REFRESH = 25; // milliseconds
document.querySelector("html").classList.add("wait");
setTimeout( () => {
  // long scripting here
  document.querySelector("html").classList.remove("wait");
}, DELAY_FOR_REFRESH);

In limited testing, the DELAY_FOR_REFRESH needed to be more than at least 20ms — any quicker and the observed behaviour is that the browser doesn't repaint/update before the long scripting gets started.

NB. the reset of cursor back to 'auto' needs to happen at the end of the setTimeout() functionality (not after it).


My mental model of what happens here is something like this:

  1. DOM is updated with change to set the 'wait' cursor
  2. Browser hasn't updated the window yet because browser has'nt had a spare CPU cycle
  3. JS schedules the work for later
  4. CPU idles, waiting until the scheduled task
  5. Browser has idle CPU now, and enough time elapses it decides to do a repaint/whatever for the change in DOM from step 1
  6. the scheduled task kicks off
  7. the scheduled task eventually finishes, including resetting the cursor
Erics
  • 803
  • 9
  • 23