1

I'm trying to run setTimeout() on a website via Firefox's Scratchpad. It seems that there were various Firefox bugs regarding this particular JavaScript method - and it's twin, setInterval(). In Firefox v.56 and the latest Waterfox (both pre-"Quantum"), these JavaScript methods do not seem to work at all. By contrast, in the Firefox "Quantum" versions, it does seem to work... That is, the very same code works in FF "Quantum", which does not work in the immediate pre-"Quantum" versions of Firefox. And yes, I've tried all sorts of variations.

Circumstance has it that I'm stuck with the pre-Quantum version(s) of Firefox for this exercise and I need to find a way to "build" this setTimeout() method from first principles, as it were.

One thought would be to take the current date/time and then loop through a check to see if, say, 10 seconds (or 5 minutes) have passed, before continuing with further code/script execution.

Any ideas how to simulate setTimeout() resource-efficiently with JavaScript but without setTimeout() or setInterval() ?


---EDIT---

False alarm... could get setInterval() to work in the older browsers too; my bad!

(this means the reason for asking the question is gone, but the question as such may remain...)


---2nd EDIT---

Whereas setTimeout() works here:

setTimeout(function(){ alert("Hello"); }, 3000);

it does not work / seems to be ignored here:

i=0;
while(i < 100)
{
 // window.open("https://www.cnn.com","_self");
 // window.open("https://www.bbc.com","_self");
   // setTimeout(function(){ alert("Hello"); }, 3000);
   setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000);
  setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000);
  alert(i);
  i++;
}
  // security mgr vetoed ???
  • Why?
nutty about natty
  • 1,267
  • 2
  • 10
  • 17
  • `loop through a check to see if, say, 10 seconds (or 5 minutes) have passed, before continuing` Wouldn't this necessarily *block*? – CertainPerformance May 12 '18 at 05:29
  • 3
    you better add code snippet. `setTimeout` works maybe even since 199x. it's more probable you misuse it rather it's broken – skyboyer May 12 '18 at 05:34
  • @skyboyer of course; added in the edit. – nutty about natty May 12 '18 at 07:25
  • so you are trying to open new popup windows. a lot. in the loop. browser just blocks this as a spam. there is nothing wrong with `setTimeout` – skyboyer May 12 '18 at 07:30
  • you can ensure there is nothing wrong with `setTimeout` with replacing `window.open` to `console.log` – skyboyer May 12 '18 at 07:32
  • @skyboyer No, the `alert(i);` is just a place-holder and that actually works (an alert is displayed on every loop); however, `window.open()` is ignored. – nutty about natty May 12 '18 at 07:37
  • hold on, under "popup window" I didn't mean `alert(i)` but all that new windows you are about to open – skyboyer May 12 '18 at 11:25
  • @skyboyer Your argument would make sense if `window.open("https://www.bbc.com","_self");` - without `setTimeout()` - would ***not*** work as well; but it does. Why would the browser only block a delayed `window.open` but not an immediate one? Also, where could I see evidence of the "blocking" (Scratchpad does not, as far as I can tell, inform the user); tried `console.log(...)` but that didn't return anything either :( – nutty about natty May 12 '18 at 17:32
  • [Popup blockers in most popular browsers will only allow a new window to be opened if it is opened as a result of code running from a direct user action such as a click. Because a `setTimeout()` happens some time in the future, is not considered the direct result of a user action so attempts to open windows from `setTimeout()` are likely blocked by the popup blocker.](https://stackoverflow.com/a/30144689/2153622) – nutty about natty May 12 '18 at 17:41
  • spawed a new, separate question from this here: https://stackoverflow.com/questions/50326060/why-is-window-open-silently-ignored-iff-called-within-settimeout/50326132#50326132 – nutty about natty May 14 '18 at 08:39

2 Answers2

3

If you really-really want to simulate the setTimeout function without blocking the browser and so on, you can try use the requestAnimationFrame function to get some delay. It should work in the Firefox 14.0+. Something like that:

function mySetTimeout (callback, timeout) {
  var startTime = performance.now();

  function mySetTimeoutRec () {
    requestAnimationFrame(function () {
      // This way this function will be called
      // asynchronously around 60 times per second
      // (or less frequently on the inactive tabs).
      // We can check that enough time has passed
      // and call the user callback or this function again.
      var currentTime = performance.now();
      var elapsedTime = currentTime - startTime;

      if (elapsedTime < timeout) {
        mySetTimeoutRec();
      } else {
        callback();
      }
    });
  }

  mySetTimeoutRec();
}

It can be used just like setTimeout:

mySetTimeout(function () { console.log('Howdy.'); }, 10 * 1000);

Anyway you should not try to do something like that in the most cases. If it seems that you are have problems with setTimeout, that's probably something else is wrong.

Nina Lisitsinskaya
  • 1,818
  • 11
  • 18
  • I thought about ´requestAnimationFrame()´ but could only find it in the context of, well, animations... – nutty about natty May 12 '18 at 06:48
  • @nuttyaboutnatty Nina gave you a perfectly good answer. You should accept it, even if your original need for an answer evaporated. She took time to formulate an answer and it's a good one. – Excel Hero Mar 29 '20 at 05:45
  • @ExcelHero I prefer to upvote - rather than accept - an answer, if there is a "mismatch" between the Q and the A, even if "the answer" may be very good / informative / well written / ... The answer I was looking for appears to be here: https://stackoverflow.com/a/50326132/2153622. Accepting an answer as an or the answer doesn't seem right if it isn't an answer. – nutty about natty Mar 29 '20 at 11:37
  • It IS an answer to the question you asked... and it is the best answer you received. – Excel Hero Mar 29 '20 at 11:51
1

One possibility would be to take advantage of a network request that takes a variable number of seconds to complete:

function artificialSetTimeout(fn, timeout) {
  const xhr = new XMLHttpRequest();
  xhr.onreadystatechange = () => {
    if (xhr.readyState === 4 && xhr.status === 200) fn();
  }
  xhr.open('get', 'https://httpstat.us/200?sleep=' + timeout);
  xhr.send();
}


console.log('start');
artificialSetTimeout(() => console.log('end'), 2000);

Don't rely on its timing to be entirely accurate, though.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320