16 points par GN⁺ 2025-09-22 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • 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 comme setImmediate, MessageChannel.postMessage, window.postMessage et scheduler.postTask
  • D’après les benchmarks réels, Chrome et Firefox appliquent un clamp à 4 ms, mais MessageChannel et scheduler.postTask fonctionnent presque sans latence, tandis que Safari limite setTimeout de 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 abus
    const 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 scripts
  • scheduler.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 : setTimeout 4.2ms, scheduler.postTask 0ms
  • Firefox 142 : setTimeout 4.72ms, scheduler.postTask 0.01ms
  • Safari 18.4 : setTimeout 26.73ms, MessageChannel 0.52ms, window.postMessage 0.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 setImmediate de Node.js est idéal, mais dans le navigateur setTimeout est inefficace
  • Dans Chrome, une tâche qui prend 300 ms peut s’allonger jusqu’à 4,8 secondes dans le navigateur
  • Comme solution, scheduler.postTask est utilisé par défaut, avec MessageChannel/window.postMessage comme 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

  • postTask et postMessage devraient rester sans throttling pendant un certain temps
  • Mais un abus de priorités élevées comme user-blocking pourrait entraîner de nouvelles interventions
  • À long terme, une autre API alternative comme scheduler2 pourrait devenir nécessaire

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.