Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

249
Visualizações
Web audio : when mobile screen turns off, setTimeout slows down

EDIT: per Yogi's comment (see "setTimeout" and "throttling" in https://developer.mozilla.org/en-US/docs/Web/API/setTimeout ), I've tried adding an AudioContext to prevent the slowdown.

document.addEventListener('click', ev => {
    let audCtxt = new AudioContext({});
});

(AudioContext needs user interaction, hence the event listener.)

But, no luck.

Other ideas I'm noting here to follow up are

  • maybe a while loop, checking Date.now() for multiples of 10ms -- but I think that would crash the page
  • maybe using requestAnimationFrame?

Original post:

I have a setTimeout firing every 0.01 seconds that's acting as a master clock for my web app.

The app plays synchronized sounds that respond to user interaction, hence the need for a master clock. Simplified:

let counter = 0;
setTimeout(() => {
    counter++;
    console.log(counter);
}, 10);

When on a mobile device, the setTimeout slows down (about 2-4x) when the screen is locked/off. (Tested on Android, not iOS).

This can be verified by logging, like the above, or by generating a sound when the counter is multiple of 100.

  1. How can I prevent this?
  2. Should I be taking a different approach to a "master clock" that synchronizes triggering audio samples while still allowing the audio to respond in real time to user interaction?
about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

setTimeout is not reliable as other things, such as promises, have higher execution priority. One possible workaround is to create a custom timer using promises. Here is an example:

var customDelay = new Promise(function (resolve) {
    var delay = 10; // milliseconds
    var before = Date.now();
    while (Date.now() < before + delay) { };
    resolve();
});

customDelay.then(function () {
    //Timer triggered
});

Update 1:

Given that you want a 10ms update frequency, running the above code on the main thread ends up locking up the UI due to the while loop. With that in mind, offloading that while loop into a web worker would resolve this. Here is some code:

<html>
<head>
  <title></title>
</head>
<body>
    <script id="FastTimer" type="javascript/worker">
        onmessage = function (event) {
            var delay = 10; // milliseconds
            var before = Date.now();
            while (Date.now() < before + delay) { };
            postMessage({data: []});
        };
    </script>
    
  <script>
    var worker;
  
    window.onload = function() {
      var blob = new Blob([document.querySelector("#FastTimer").textContent]);
      blobURL = window.URL.createObjectURL(blob);

      worker = new Worker(blobURL);
      
      worker.addEventListener("message", receivedWorkerMessage);
      worker.onerror = workerError;

      //Start the worker.
      worker.postMessage({});
    }

    var counter = 0;
    
    function receivedWorkerMessage(event) {
        worker.postMessage({});
        timerTiggered();
    }

    function timerTiggered() {
        counter++;
        console.log(counter);
    }

    function workerError(error) {
      alert(error.message);
    }

    function stopWorker() {
      worker.terminate();
      worker = null;
    }
  </script>
</body>
</html>

The main issue with the above is that I suspect there would be some sort of time cost going back and forth between the worker (maybe a couple ms, hard to say).

As mentioned, normally requestAnimationFrame is used for animations in web apps. However, this would likely not fire when the screen is locked. But if you want to try, here is a sample:

<html>
<head>
  <title></title>
</head>
<body>
  <script>
    var counter = 0;
    var minTimeSpan = 10;
    var lastTime = performance.now();
    
    function animate() {
        let t = performance.now();

        if (t - lastTime >= minTimeSpan) {
            timerTiggered();
        }
    
        requestAnimationFrame(animate);
    }
    
    function timerTiggered() {
        counter++;
        console.log(counter);
    }
    
    animate();
  </script>
</body>
</html>
about 4 years ago · Juan Pablo Isaza Relatório

0

This can usually be solved by using a Web Worker for running the timer. I created a library which looks like setTimeout() but uses a Web Worker internally.

https://github.com/chrisguttandin/worker-timers

But there was a bug a while ago in some browser (I forgot which one it was) which caused this to not work any longer. Therefore I built the same abstraction on top of a running AudioContext.

https://github.com/chrisguttandin/audio-context-timers

But as you already said this only works if the page is already allowed to run an AudioContext by starting one in response to a click handler.

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda