Pourquoi les navigateurs limitent les timers JavaScript
(nolanlawson.com)- En JavaScript,
setTimeout(0)ne s’exécute pas réellement immédiatement et subit souvent un délai minimal de 4 ms, une limite par défaut imposée par les navigateurs pour éviter les abus - Cette contrainte vise à empêcher les sites web d’abuser des timers de façon incontrôlée et de provoquer une consommation de batterie excessive ou une dégradation des interactions ; elle peut être renforcée à 16 ms en mode batterie et à 1 seconde dans les onglets en arrière-plan
- Pour contourner les limites de
setTimeout, les développeurs ont utilisé diverses API de timers alternatives commesetImmediate,MessageChannel.postMessage,window.postMessageetscheduler.postTask - D’après les benchmarks réels, Chrome et Firefox appliquent un clamp à 4 ms, mais
MessageChanneletscheduler.postTaskfonctionnent presque sans latence, tandis que Safari limitesetTimeoutde façon plus agressive - Au fond, il s’agit d’un problème d’équilibre entre la protection de l’expérience utilisateur et la liberté des développeurs ; aujourd’hui, la Scheduler API s’impose comme solution standardisée, même si de nouvelles interventions des navigateurs (Intervention) pourraient apparaître en cas d’abus
Contexte des limitations de setTimeout
- Même avec
setTimeout(0), l’exécution réelle a souvent lieu au minimum 4 ms plus tard à cause des abusconst start = performance.now() setTimeout(() => { // Exécuté après environ 4 ms console.log(performance.now() - start) }, 0) - L’objectif est de réduire la consommation de batterie et les retards de rendu en empêchant les appels répétés sans contrôle
- Certains navigateurs renforcent ces limites selon le contexte
- Mode batterie : 16 ms dans l’ancien Edge
- Onglet en arrière-plan : jusqu’à 1 seconde de délai dans Chrome
L’apparition d’autres API de timers
setImmediate: pris en charge uniquement par IE et l’ancien Edge, aujourd’hui pratiquement abandonnéMessageChannel.postMessage: transmet une tâche à la boucle d’événements via un canal séparéwindow.postMessage: bonnes performances, mais risque de conflit avec d’autres scriptsscheduler.postTask: pris en charge par les navigateurs récents et considéré comme le choix le plus fiable
Résultats des benchmarks (MacBook Pro 2021, 101 itérations)
- Chrome 139 :
setTimeout4.2ms,scheduler.postTask0ms - Firefox 142 :
setTimeout4.72ms,scheduler.postTask0.01ms - Safari 18.4 :
setTimeout26.73ms,MessageChannel0.52ms,window.postMessage0.05ms
Le cas de fake-indexeddb
- IndexedDB souhaite un commit automatique de transaction juste après la fin des microtasks de la boucle d’événements
- Le
setImmediatede Node.js est idéal, mais dans le navigateursetTimeoutest inefficace - Dans Chrome, une tâche qui prend 300 ms peut s’allonger jusqu’à 4,8 secondes dans le navigateur
- Comme solution,
scheduler.postTaskest utilisé par défaut, avecMessageChannel/window.postMessagecomme fallback pour la compatibilité
Le débat sur l’intervention des navigateurs
- Un camp affirme qu’il faut limiter les timers pour que les développeurs soient protégés d’eux-mêmes
- L’autre estime qu’il faut garantir la liberté des développeurs afin qu’ils puissent mesurer et optimiser par eux-mêmes
- Au final, selon le principe de priorité à l’utilisateur, les navigateurs interviennent pour empêcher les abus
- La Scheduler API tente de concilier ces deux positions en donnant aux développeurs un contrôle fin des tâches tout en s’alignant sur le pipeline de rendu du navigateur
Perspectives
postTasketpostMessagedevraient rester sans throttling pendant un certain temps- Mais un abus de priorités élevées comme
user-blockingpourrait entraîner de nouvelles interventions - À long terme, une autre API alternative comme
scheduler2pourrait devenir nécessaire
Aucun commentaire pour le moment.