Je testais la précision de setTimeout
en utilisant ce test . Maintenant, j'ai remarqué que (comme prévu) setTimeout
n'est pas très précis, mais qu'il n'est pas extrêmement inexact pour la plupart des appliances. Maintenant, si je lance le test dans Chrome et le laisse fonctionner dans un onglet en arrière-plan (donc, passer à un autre onglet et naviguer là-bas), revenir au test et inspecter les résultats (si le test terminé) elles ont été radicalement modifiées.Il semble que les délais d'attente aient été beaucoup plus lents.
On dirait donc que Chrome suspend ou du moins ralentit l’exécution de javascript dans un onglet non ciblé. Impossible de trouver beaucoup d'informations sur le réseau à ce sujet. Cela signifierait que nous ne pouvons pas exécuter des tâches en arrière-plan, comme par exemple vérifier périodiquement sur un serveur à l'aide d'appels XHR et setInterval
(je suppose que le même comportement se présente pour setInterval
, écrira un test si le temps passe avec moi).
Quelqu'un at-il rencontré cela? Y aurait-il une solution de contournement pour cette suspension/ralentissement? Souhaitez-vous appeler cela un bug et devrais-je le classer comme tel?
J'ai récemment demandé à ce sujet et c'est un comportement par conception. Lorsqu'un onglet est inactif, la fonction est appelée au maximum une fois par seconde. Voici le changement de code .
Cela aidera peut-être: Comment puis-je faire en sorte que setInterval fonctionne également lorsqu'un onglet est inactif dans Chrome?
TL; DR: utiliser Web Workers .
Il existe une solution pour utiliser les travailleurs Web, car ils s'exécutent dans un processus distinct et ne sont pas ralentis.
J'ai écrit un petit script qui peut être utilisé sans modifier votre code. Il remplace simplement les fonctions setTimeout, clearTimeout, setInterval, clearInterval.
Il suffit de l'inclure avant tout votre code
Jouer un son ~ vide force le navigateur à conserver la performance - je l’ai découvert après avoir lu ce commentaire: Comment faire en sorte que JavaScript s'exécute à vitesse normale dans Chrome même lorsque l'onglet n'est pas actif ?
J'ai besoin de performances illimitées à la demande pour un jeu sur navigateur qui utilise WebSockets. Je sais par expérience que l'utilisation de WebSockets n'assure pas des performances illimitées, mais que des tests permettent de lire un fichier audio.
Voici 2 boucles audio vides que j'ai créées à cet effet, vous pouvez les utiliser librement et commercialement: http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogghttp: // adventure .land/sounds/loops/empty_loop_for_js_performance.wav
(Ils incluent le bruit -58db, -60db ne fonctionne pas)
Je les joue, à la demande de l'utilisateur, avec Howler.js: https://github.com/goldfire/howler.js
function performance_trick()
{
if(sounds.empty) return sounds.empty.play();
sounds.empty = new Howl({
src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
volume:0.5,
autoplay: true, loop: true,
});
}
Il est regrettable qu’il n’existe pas de méthode intégrée permettant d’activer/désactiver les performances javascript complètes par défaut. Pourtant, les mineurs de chiffrement peuvent détourner tous vos fils de calcul à l’aide de Web Workers sans invite: |
J'ai publié le package worker-interval npm qui implémentait setInterval et clearInterval avec l'utilisation de Web-Workers pour rester opérationnel sur les onglets inactifs pour Chrome, Firefox et IE.
La plupart des navigateurs modernes (Chrome, Firefox et IE), ainsi que les intervalles (minuteries de fenêtre) ne doivent pas être activés plus d'une fois par seconde dans des onglets inactifs.
Vous pouvez trouver plus d'informations sur
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
J'ai mis à jour mon noyau jQuery à la version 1.9.1, ce qui a permis de résoudre l'écart entre intervalles dans les onglets inactifs. Je voudrais essayer cela en premier, puis examiner d'autres options de substitution de code.
voici ma solution qui récupère la milliseconde actuelle et la compare à la milliseconde de création de la fonction. pour intervalle, il mettra à jour la milliseconde lorsqu'il exécutera la fonction. vous pouvez également saisir l'intervalle/timeout par un identifiant.
<script>
var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];
function getCurrentMillis(){
var d = new Date();
var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
return now;
}
function setAccurateTimeout(callbackfunction, millis, id=0){
nowMillisTimeout[id] = getCurrentMillis();
timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}
function setAccurateInterval(callbackfunction, millis, id=0){
nowMillisInterval[id] = getCurrentMillis();
interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}
//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);
setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);
</script>