Utilisation de setTimeout pour améliorer la réactivité

Lorsque vous cherchez à améliorer les performances d'une page, une technique que je n'ai pas mentionnée précédemment utilise SetTimeout pour éviter que javascript ne supporte le rendu d'une page.

Par exemple, imaginez que nous avons une partie de jQuery particulièrement longue en ligne avec le html:

$('input').click(function () { // Do stuff }); 

Si ce code est en ligne, nous maintenons l'exécution perçue de la page alors que la partie de jquery est occupée à joindre un gestionnaire de clics à chaque entrée de la page.

Serait-il judicieux de générer un nouveau fil à la place:

 setTimeout(function() { $('input').click(function () { // Do stuff }) }, 100); 

Le seul inconvénient que je vois est qu'il existe maintenant une plus grande chance que l'utilisateur clique sur un élément avant que le gestionnaire de clics ne soit joint. Cependant, ce risque peut être acceptable et nous avons un degré de ce risque de toute façon, même sans setTimeout.

Ai-je raison, ou ai-je tort?

La technique actuelle consiste à utiliser setTimeout avec un temps de 0.

Cela fonctionne car JavaScript est simple. Un délai d'attente ne provoque pas que le navigateur génère un autre thread, et ne garantit pas non plus que le code s'exécute à l'heure spécifiée. Toutefois, le code sera exécuté lorsque les deux:

  1. Le temps spécifié s'est écoulé.
  2. Le contrôle d'exécution est remis au navigateur.

Par conséquent, appeler setTimeout avec un temps de 0 peut être considéré comme temporairement livré au navigateur.

Cela signifie que si vous disposez d'un code long, vous pouvez simuler un multi-threading en produisant régulièrement avec setTimeout . Votre code peut ressembler à ceci:

 var batches = [...]; // Some array var currentBatch = 0; // Start long-running code, whenever browser is ready setTimeout(doBatch, 0); function doBatch() { if (currentBatch < batches.length) { // Do stuff with batches[currentBatch] currentBatch++; setTimeout(doBatch, 0); } } 

Remarque : Bien qu'il soit utile de connaître cette technique dans certains scénarios , je doute fortement que vous en auriez besoin dans la situation que vous décrivez (en assignant les gestionnaires d'événements sur DOM prêts). Si la performance est en effet un problème, je suggérerais chercher des moyens d'améliorer la performance réelle en modifiant le sélecteur.

Par exemple, si vous n'avez qu'un seul formulaire sur la page qui contient <input> s, donnez le <form> une ID et utilisez $('#someId input') .

setTimeout() peut être utilisé pour améliorer le temps de chargement "perçu" – mais pas comme vous l'avez montré. L'utilisation de setTimeout() ne provoque pas que votre code s'exécute dans un thread distinct. Au lieu de cela, setTimeout() renvoie simplement le thread au navigateur pour (approximativement) le délai spécifié. Quand il est temps que votre fonction s'exécute, le navigateur renverra le thread au moteur javascript. Dans javascript, il n'y a jamais plus d'un thread (sauf si vous utilisez quelque chose comme « Web Workers »).

Donc, si vous souhaitez utiliser setTimeout() pour améliorer les performances lors d'une tâche à forte intensité de calcul, vous devez casser cette tâche en petits morceaux et les exécuter en ordre, en les chaînant en utilisant setTimeout() . Quelque chose comme ça fonctionne bien:

 function runTasks( tasks, idx ) { idx = idx || 0; tasks[idx++](); if( idx < tasks.length ) { setTimeout( function(){ runTasks(tasks, idx); },1); } } runTasks([ function() { /* do first part */ }, function() { /* do next part */ }, function() { /* do final part */ } ]); 

Remarque:

  1. Les fonctions sont exécutées dans l'ordre. Il peut y avoir autant que vous avez besoin.
  2. Lorsque la première fonction retourne, la suivante est appelée via setTimeout() .
  3. La valeur de temporisation que j'ai utilisée est 1 . Ceci est suffisant pour provoquer un rendement , et le navigateur prend le fil s'il en a besoin ou permet à la prochaine tâche de procéder s'il y a du temps. Vous pouvez expérimenter avec d'autres valeurs si vous ressentez le besoin, mais en général 1 est ce que vous voulez pour ces buts.

Vous avez raison, il y a une plus grande chance d'un clic "manqué", mais avec une faible valeur d'expiration, c'est très peu probable.