Comment rendre la main au thread principal pour améliorer l'INP
Utilisez scheduler.yield() pour fractionner les tâches longues et maintenir la réactivité de vos pages

Rendre la main au thread principal
Imaginez un film romantique. Le décor est un petit marché français au centre d'un petit village. Les rues sont remplies de couples buvant du café, mangeant des croissants et achetant des fleurs. Imaginez maintenant ce qui se passe si un seul acheteur peut effectuer un achat auprès d'un vendeur à la fois, tandis que tous les autres doivent attendre leur tour. Le boulanger est submergé de demandes, des disputes éclatent chez le fleuriste et la promenade romantique se transforme en une attente frustrante.
Eh bien... c'est un peu ce qui se passe sur un site web lorsque les choses deviennent trop chargées.
Dernière révision par [url=https:\/\/www.linkedin.com\/in\/arjenkarel\/]Arjen Karel[\/url] en mars 2026
Pourquoi rendre la main (yielding) est important pour l'INP
Le thread principal d'un navigateur gère tous les processus importants : l'analyse du HTML et du CSS, l'exécution du JavaScript, la gestion des événements d'entrée comme les clics et les défilements, et le rendu visuel. Il fonctionne sur un modèle mono-thread, ce qui signifie qu'il ne peut effectuer qu'une seule tâche à la fois. Lorsqu'une tâche commence à s'exécuter, le navigateur l'exécute jusqu'à son terme et ne s'arrête pas avant qu'elle ne soit finie. Aucune autre tâche n'est planifiée tant que la tâche actuelle n'est pas terminée. C'est ce qu'on appelle bloquer le thread principal.
Le blocage du thread principal est la cause première des mauvais scores [url=\/core-web-vitals\/interaction-to-next-paint]Interaction to Next Paint (INP)[\/url]. Lorsqu'un visiteur clique sur un bouton et que votre JavaScript bloque le thread principal pendant 200 ms, le navigateur ne peut pas afficher de réponse tant que le script n'est pas terminé. La phase de [url=\/core-web-vitals\/interaction-to-next-paint\/processing-time]processing time[\/url] de l'INP mesure précisément ce délai. Selon le [url=https:\/\/almanac.httparchive.org\/en\/2025\/performance]Web Almanac 2025[\/url], le temps de blocage total (Total Blocking Time) mobile médian est de 1 916 ms, en hausse de 58 % par rapport à l'année précédente. Cela représente près de 2 secondes pendant lesquelles le navigateur ne peut pas répondre aux entrées de l'utilisateur.
Une façon de corriger cela est de rendre la main (yielding) au thread principal. Le yielding est une technique où les tâches longues sont fractionnées en plusieurs tâches plus petites pour permettre au navigateur de gérer des travaux plus importants (comme répondre aux entrées de l'utilisateur) entre elles.
Tâches longues et période de blocage : lorsqu'une tâche prend plus de 50 millisecondes, elle est classée comme une tâche longue, et tout ce qui dépasse ce seuil de 50 millisecondes est appelé "période de blocage" de la tâche. Fractionner ces tâches longues en morceaux plus petits permet au navigateur de rester réactif, même lors de la gestion d'opérations gourmandes en calcul.
Anciennes stratégies de yielding
Avant l'[url=https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Prioritized_Task_Scheduling_API]API Prioritized Task Scheduling[\/url], il existait 4 façons de rendre la main au thread principal. Toutes ont des limites.
- setTimeout() : la stratégie la plus courante.
setTimeout() avec un délai de 0 ajoute la tâche à la fin de la file d'attente, permettant aux autres tâches de s'exécuter en premier. Le problème : les tâches ne peuvent être poussées qu'à la fin de la file d'attente, de sorte que d'autres scripts peuvent passer devant avant que votre code ne reprenne. Les appelssetTimeout() imbriqués imposent également un délai minimum de 5 ms après cinq rounds.- requestAnimationFrame() : place une fonction en file d'attente pour qu'elle s'exécute avant le prochain rafraîchissement (repaint) du navigateur. Souvent combiné avec
setTimeout() pour s'assurer que les rappels (callbacks) sont planifiés après la prochaine mise à jour de la mise en page (layout). Pas conçu pour le yielding, mais pour le travail d'animation.- requestIdleCallback() : mieux adapté aux tâches non critiques et de faible priorité qui peuvent s'exécuter pendant les temps d'arrêt du navigateur. La limite : il n'y a aucune garantie que les tâches planifiées s'exécuteront rapidement (ou même du tout) sur un thread principal occupé.
- isInputPending() : vérifie les entrées utilisateur en attente et ne rend la main que si une entrée est détectée. [url=https:\/\/web.dev\/articles\/optimize-long-tasks]Google ne recommande plus cette approche[\/url]. Elle peut renvoyer des faux négatifs et ne tient pas compte d'autres travaux critiques pour la performance comme les animations et les mises à jour de rendu.
scheduler.yield()
Les limites de ces méthodes ont été une préoccupation pour l'équipe Chrome, d'autant plus que de nombreux sites échouent à l'[url=\/core-web-vitals\/interaction-to-next-paint]INP[\/url]. Pour remédier à cela, ils ont créé
scheduler.yield() : une nouvelle API qui permet aux développeurs de rendre la main au thread principal immédiatement sans réorganiser l'ordre des tâches ni ajouter de complexité.scheduler.yield() a été [url=https:\/\/developer.chrome.com\/blog\/new-in-chrome-129]déployé en version stable dans Chrome 129[\/url] (septembre 2024) et est désormais supporté par tous les principaux navigateurs, à l'exception de Safari.Exemple de code
Puisque Safari ne supporte pas encore
scheduler.yield(), utilisez une solution de repli (fallback) avecsetTimeout() :function yieldToMain() { if ('scheduler' in window && 'yield' in window.scheduler) { return window.scheduler.yield(); } return new Promise((resolve) => { setTimeout(resolve, 0); }); }La fonction
yieldToMain() vérifie siwindow.scheduler.yield existe. Si c'est le cas, elle utilise l'API native. Sinon, le code se replie sursetTimeout(). Cela correspond au [url=https:\/\/web.dev\/articles\/optimize-long-tasks]modèle recommandé par Google[\/url].Pour les projets qui ont besoin de l'API Prioritized Task Scheduling complète (y compris
scheduler.postTask() etTaskController), Google Chrome Labs maintient un [url=https:\/\/github.com\/nicjgriffin\/nicj-scheduler-polyfill]polyfill officiel[\/url].Exemple concret : améliorer la recherche avec yieldToMain()
Voici comment
yieldToMain() peut améliorer l'expérience de recherche pour vos utilisateurs.La fonction
handleSearch() met d'abord à jour le contenu du bouton pour donner un retour immédiat qu'une recherche est en cours, puis rend la main pour permettre au navigateur d'afficher cette mise à jour. Ensuite,fetchData() récupère les données de recherche etupdateHTML(data) affiche les résultats. Un autreyieldToMain() assure une mise à jour rapide de la mise en page. Enfin, les tâches moins importantes sont planifiées pendant le temps d'inactivité du navigateur. Notez que je n'ai pas rendu la main avantrequestIdleCallback() puisqu'il ne s'exécute de toute façon que lorsque le thread principal est inactif.async function handleSearch() { \/* mettre à jour rapidement le contenu du bouton après l'envoi *\/ updateButtonToPending(); \/* Rendre la main au thread principal *\/ await yieldToMain(); \/* récupérer les données et mettre à jour le HTML *\/ const data = await fetchData(); updateHTML(data); \/* Rendre à nouveau la main au thread principal *\/ await yieldToMain(); \/* certaines fonctions ne devraient s'exécuter que pendant le temps d'inactivité du navigateur *\/ requestIdleCallback(sendDataToAnalytics); }Pour un autre exemple pratique, découvrez comment [url=\/pagespeed\/datalayer-inp-yield-pattern]utiliser ce même modèle de yield avec les poussées dataLayer[\/url] pour empêcher les scripts d'analyse de bloquer les interactions.
Pourquoi scheduler.yield() est meilleur
Contrairement à
setTimeout(), qui ajoute les tâches différées à la fin de la file d'attente des tâches,scheduler.yield() interrompt l'exécution et place la suite en tête de la file d'attente. Votre code reprend dès que les travaux de plus haute priorité (comme la gestion des rappels d'entrée) sont terminés. C'est la différence clé : vous pouvez rendre la main au thread principal sans risquer que d'autres scripts ne passent devant avant que votre code ne reprenne.
scheduler.yield() est également conçu pour fonctionner avec l'API Prioritized Task Scheduling. Lorsqu'il est appelé à l'intérieur d'un rappelscheduler.postTask(),scheduler.yield() hérite du niveau de priorité de la tâche. Cette combinaison vous donne un contrôle précis sur la manière dont votre [url=\/pagespeed\/javascript-priority-levels]JavaScript est priorisé[\/url] et sur le moment où il rend la main.Support des navigateurs
scheduler.yield() est supporté par [url=https:\/\/caniuse.com\/mdn-api_scheduler_yield]71,5 % des navigateurs dans le monde[\/url] :- Chrome 129+ et Edge 129+ : stable depuis septembre 2024
- Firefox 142+ : stable depuis août 2025
- Safari : non supporté, aucun calendrier annoncé
La solution de repli
setTimeout() dans la fonctionyieldToMain() ci-dessus garantit que votre code fonctionne dans tous les navigateurs. Les utilisateurs de Safari bénéficient de l'ancien comportement où les suites vont à la fin de la file d'attente, mais la page rend tout de même la main. À mesure que le support des navigateurs se développe, davantage d'utilisateurs bénéficieront automatiquement d'une reprise plus rapide.Si le problème vient de scripts tiers bloquant entièrement le thread principal, le fait de [url=\/pagespeed\/14-methods-to-defer-javascript]différer ces scripts[\/url] est une meilleure première étape que le yielding. Le yielding aide lorsque votre propre code doit effectuer beaucoup de travail mais que vous voulez que le navigateur reste réactif entre les morceaux.
Pour vérifier que le yielding améliore votre INP sur le terrain, surveillez vos pages avec le [url=https:\/\/coredash.app]Real User Monitoring[\/url]. Les outils de laboratoire comme Lighthouse mesurent le temps de blocage total (Total Blocking Time), mais seules les données de terrain montrent l'INP réel vécu par vos visiteurs. [include]cwv\/authorbio.html[\/include]
[include]sidebar.html[\/include] [include]blogfooter.html[\/include]

- Firefox 142+ : stable depuis août 2025
- requestAnimationFrame() : place une fonction en file d'attente pour qu'elle s'exécute avant le prochain rafraîchissement (repaint) du navigateur. Souvent combiné avec