Est-il une façon plus précise afin de créer un Javascript timer que setTimeout?
Quelque chose qui m'a toujours ennuyé est la façon imprévisible, les setTimeout()
méthode en Javascript est.
Dans mon expérience, la minuterie est horriblement inexactes dans beaucoup de situations. Par inexactes, je veux dire le délai réel le temps semble varier de 250 à 500 ms plus ou moins. Bien que ce n'est pas une énorme quantité de temps, lorsque vous l'utilisez pour afficher/masquer les éléments de l'INTERFACE utilisateur à la fois peut être visible.
Y a des trucs qui peut être fait pour s'assurer que setTimeout()
effectue avec précision (sans avoir recours à une API externe) ou est-ce une cause perdue?
Vous devez vous connecter pour publier un commentaire.
Non et non. Vous n'allez pas pour obtenir quelque chose de proche de un parfaitement exacte de la minuterie avec
setTimeout()
les navigateurs ne sont pas mis en place pour cela. Cependant, vous n'avez pas besoin de compter sur elle pour le calendrier de choses. La plupart d'animation des bibliothèques compris cela il y a des années: vous mettez en place un callback avecsetTimeout()
, mais de déterminer ce qui doit être fait sur la base de la valeur de(new Date()).milliseconds
(ou l'équivalent). Cela vous permet de profiter de la plus fiable de la minuterie de support dans les navigateurs les plus récents, tout en continuant à se comporter de manière appropriée sur les navigateurs plus anciens.Il vous permet également de éviter d'utiliser trop de minuteries! Ceci est important: chaque horloge est un rappel. Chaque rappel exécute du code JS. Tout code JS est en cours d'exécution, le navigateur d'événements, y compris d'autres rappels - sont retardés ou supprimés. Lorsque le rappel de finitions, d'autres rappels doit rivaliser avec d'autres événements de navigateur pour avoir une chance de s'exécuter. Par conséquent, une minuterie qui gère toutes les tâches en attente pour cet intervalle sera de faire mieux que les deux horloges avec coïncidant intervalles, et (pour les courts délais d'attente) mieux que deux minuteries avec chevauchement des délais d'attente!
Résumé: arrêtez d'utiliser
setTimeout()
à mettre en œuvre "une minuterie /une tâche" de dessins, et d'utiliser l'horloge en temps réel afin de lisser les actions d'INTERFACE utilisateur.requestAnimationFrame
maintenant... Voir aussi cette réponse par Chris. Il n'est pas simple d'une solution, mais il satisfait aux OP les critères de l'extérieur ni de l'API..
REF; http://www.sitepoint.com/creating-accurate-timers-in-javascript/
Ce site écopé moi sur une grande échelle.
Vous pouvez utiliser l'horloge du système pour compenser la minuterie de l'inexactitude. Si vous exécutez une fonction de synchronisation comme une série de setTimeout appels — chaque instance d'appeler le prochain — alors tout ce que vous avez à faire pour le garder précis, c'est exactement la façon dont il est inexact, et de soustraire cette différence à partir de la prochaine itération:
Cette méthode permettra de réduire au minimum la dérive et de réduire les imprécisions par plus de 90%.
Il fixe mes questions, j'espère que ça aide
elapsed
variable dans ton code?doTimer
fonction à la fin de l'article est exactement ce dont j'avais besoin. C'est super précis.J'ai eu un problème similaire n'y a pas longtemps et est venu avec une approche qui combine
requestAnimationFrame
avec la performance.maintenant (), qui fonctionne de façon très efficace.Im maintenant en mesure de faire de timers précis à environ 12 décimales:
http://jsfiddle.net/CGWGreen/9pg9L/
shog9 la réponse est à peu près ce que je dis, bien que je serais ajouter ce qui suit à propos de l'INTERFACE utilisateur et d'animation d'événements:
Si vous avez une boîte qui est censé le faire glisser sur l'écran, s'étendent vers le bas, puis fondu dans son contenu, n'essayez pas de faire tous les trois événements distincts avec des délais programmée pour faire le feu l'un après l'autre - utilisez des rappels, donc une fois que le premier événement est terminé le faisant glisser les appels de l'expanseur, une fois cela fait, elle appelle le fader. jQuery pouvez le faire facilement, et je suis sûr que d'autres bibliothèques peuvent ainsi.
Si vous avez besoin d'obtenir une précision rappel sur un intervalle donné, ce gist peuvent vous aider à:
https://gist.github.com/1185904
Si vous utilisez
setTimeout()
de céder rapidement le navigateur il est donc thread de l'INTERFACE utilisateur de rattraper toutes les tâches qu'il doit faire (comme la mise à jour de l'onglet ou de ne pas montrer le Long d'exécuter le Script de dialogue), il y a une nouvelle API appelée Efficace Script Rendement, aka,setImmediate()
qui peuvent travailler un peu mieux pour vous.setImmediate()
fonctionne de façon très similaire auxsetTimeout()
, mais il peut l'exécuter immédiatement si le navigateur n'a rien d'autre à faire. Dans beaucoup de situations où vous utilisezsetTimeout(..., 16)
ousetTimeout(..., 4)
ousetTimeout(..., 0)
(c'est à dire que vous souhaitez que le navigateur d'exécuter n'importe quel suspens thread d'INTERFACE utilisateur tâches et ne montrent pas une Longue Course Script de dialogue), vous pouvez simplement remplacer votresetTimeout()
avecsetImmediate()
, l'abandon de la deuxième (milliseconde) argument.La différence avec
setImmediate()
est qu'il est fondamentalement un rendement; si le navigateur a parfois à faire sur le thread d'INTERFACE utilisateur (par exemple, mise à jour d'un onglet), il va faire avant de retourner à votre rappel. Toutefois, si le navigateur est déjà tous pris par son travail, le rappel spécifié danssetImmediate()
consistera essentiellement à exécuter sans délai.Malheureusement, il n'est actuellement pris en charge dans IE9+, comme il existe des repousser de l'autre les fournisseurs de navigateur.
Il y a un bon polyfill disponible, si vous souhaitez l'utiliser et j'espère que les autres navigateurs appliquent à un certain point.
Si vous utilisez
setTimeout()
pour l'animation, requestAnimationFrame est votre meilleur pari que votre code fonctionne en synchronisation avec la fréquence d'actualisation du moniteur.Si vous utilisez
setTimeout()
sur un ralentissement de la cadence, par exemple, une fois tous les 300 millisecondes, vous pouvez utiliser une solution similaire à ce que user1213320 suggère, où vous surveiller combien de temps il a été depuis le dernier timestamp votre minuterie couru et de compenser pour tout retard. Une amélioration est que vous pouvez utiliser la nouvelle Haute Résolution En Temps interface (akawindow.performance.now()
) au lieu deDate.now()
pour obtenir plus de milliseconde à l'heure actuelle.Vous avez besoin de "glisser" sur la cible. Quelques essais et d'erreur sera nécessaire, mais dans l'essence.
Définir un délai d'attente pour terminer autour de 100ms avant le moment
faire de la temporisation de la fonction du gestionnaire comme ceci:
Mais votre boucle while peut toujours être interrompue par d'autres processus, donc c'est pas encore parfait.
Voici un exemple de démo Shog9 de la suggestion. Cela remplit un jquery, la barre de progression en douceur sur les 6 secondes, puis redirige vers une autre page, une fois qu'il est rempli:
setTimeout()
. Je vais modifier en conséquence.C'est un minuteur que j'ai fait pour un projet de musique de la mine, qui ne cette chose. Timer précis sur tous les appareils.
JS:
Déteste dire ça, mais je ne pense pas qu'il y est une façon de résoudre cela. Je pense que cela dépend sur le système client, bien que, d'un moteur javascript plus rapide ou la machine peut faire légèrement plus précis.
De mon expérience, c'est perdu d'effort, même le plus petit montant raisonnable de temps je l'ai jamais reconnu js loi est autour de 32-33 mme. ...
Il y a certainement une limite. Pour vous donner un peu de perspective, le navigateur Chrome de Google vient de sortir est assez rapide qu'il peut exécuter setTimeout(function() {}, 0) dans 15 à 20 ms alors que les anciens moteurs Javascript a pris des centaines de millisecondes pour l'exécution de cette fonction. Bien que setTimeout utilise millisecondes, pas de javascript de la machine virtuelle à ce point dans le temps peut exécuter du code avec précision.
Dan, d'après mon expérience (qui comprend la mise en oeuvre de SMIL2.1 langue en JavaScript, où la gestion du temps est dans le sujet) je peux vous assurer que vous avez réellement jamais besoin d'une grande précision de setTimeout ou setInterval.
Ce n'est cependant question est l'ordre dans lequel setTimeout/setInterval à exécuter lors de l'attente - et qui fonctionne toujours parfaitement.
JavaScript délais d'attente ont un defacto limite de 10-15ms (je ne suis pas sûr de ce que vous faites pour obtenir 200ms, sauf si vous êtes en train de faire 185ms de réels js exécution). Cela est dû à windows standard résolution du timer de 15ms, le seul moyen de faire mieux, c'est d'utiliser des Fenêtres supérieures de la résolution des minuteries qui est un vaste système de réglage peut donc vis avec d'autres applications sur le système et aussi la mâche de vie de la batterie (Chrome a un bug d'Intel sur cette question).
Le standard de facto de 10-15ms est à cause de gens à l'aide de 0ms délais d'attente sur les sites web, mais alors le codage d'une manière qui suppose que suppose un 10-15ms délai d'attente (par exemple. js jeux qui prennent en 60fps mais demandez 0ms/cadre avec pas de delta logic donc le jeu/site/animation passe quelques ordres de grandeur plus rapide que prévu). Compte que, même sur les plates-formes qui n'ont pas windows minuterie problèmes, les navigateurs minuteur de limite de résolution de 10ms.
Voici ce que j'utilise. Puisque c'est du JavaScript, je vais poster mon Frontend et node.js solutions:
Pour les deux, j'utilise le même décimal arrondi de la fonction que je vous recommande vivement de tenir à bout de bras parce que les raisons:
places
- Nombre de décimales à qui à tour, ce devrait être à l'abri et éviter tout problème avec des flotteurs (certains numéros comme 1.0000000000005~ peut être problématique). J'ai Passé du temps à étudier le meilleur moyen pour arrondir les décimales de la haute résolution des minuteries converti à quelques millisecondes.that + symbol
- C'est un opérateur unaire qui convertit l'opérande en nombre, pratiquement identiques àNumber()
Vous pourriez envisager d'utiliser la html5 webaudio horloge qui utilise l'heure du système pour améliorer la précision de