Maison > Article > interface Web > Introduction aux méthodes d'optimisation des performances JavaScript (avec exemples)
Cet article vous présente une introduction aux méthodes d'optimisation des performances JavaScript (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Cet article est principalement après avoir lu "Javascript haute performance", je souhaite enregistrer quelques solutions d'optimisation utiles et partager certaines de mes propres expériences avec tout le monde,
Chargement et exécution de Javascript
Comme nous le savons tous, lorsque le navigateur analyse l'arborescence DOM, lorsqu'il analyse la balise de script, il bloque toutes les autres tâches jusqu'à ce que le fichier js soit téléchargé une fois l'exécution de l'analyse terminée. , l'exécution continuera. Par conséquent, le navigateur sera bloqué ici à ce moment-là. Si la balise de script est placée dans l'en-tête, l'utilisateur ne peut voir qu'une page vierge avant que le fichier js ne soit chargé et exécuté. Cette expérience utilisateur doit être particulièrement mauvaise. À cet égard, les méthodes couramment utilisées sont les suivantes :
Placez toutes les balises de script en bas du corps. Cela garantit que le fichier js est chargé et exécuté en dernier, ainsi que la page. peut être affiché en premier aux utilisateurs. Cependant, vous devez d'abord savoir si le rendu de la page sur le premier écran dépend de certains de vos fichiers js. Si c'est le cas, vous devez mettre cette partie du fichier js en tête.
Utilisez le report, comme l'écriture suivante. Lors de l'utilisation de defer, bien que le navigateur télécharge le fichier js correspondant lorsqu'il analyse la balise, il ne l'exécutera pas immédiatement, il attendra que le DOM soit analysé (avant DomContentLoader) avant d'exécuter ces fichiers js. Le navigateur ne sera donc pas bloqué.
<script src="test.js" type="text/javascript" defer></script>
Chargement dynamique des fichiers js De cette façon, vous pouvez charger le code requis une fois la page chargée. Vous pouvez également utiliser ceci. plusieurs façons d'implémenter le chargement paresseux/à la demande de fichiers js. Par exemple, il est plus courant maintenant que webpack soit combiné avec vue-router/react-router pour implémenter le chargement à la demande. un itinéraire spécifique est accessible. La méthode spécifique est la suivante :
1. Insérez dynamiquement des balises de script pour charger des scripts, par exemple via le code suivant
function loadScript(url, callback) { const script = document.createElement('script'); script.type = 'text/javascript'; // 处理IE if (script.readyState) { script.onreadystatechange = function () { if (script.readyState === 'loaded' || script.readyState === 'complete') { script.onreadystatechange = null; callback(); } } } else { // 处理其他浏览器的情况 script.onload = function () { callback(); } } script.src = url; document.body.append(script); } // 动态加载js loadScript('file.js', function () { console.log('加载完成'); })
2. Chargez les fichiers js via xhr, Cependant, si vous utilisez cette méthode, vous risquez de rencontrer des problèmes inter-domaines. Les exemples sont les suivants :
const xhr = new XMLHttpRequest(); xhr.open('get', 'file.js'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) { const script = document.createElement('script'); script.type = 'text/javascript'; script.text = xhr.responseText; document.body.append(script); } } }
3. Fusionnez plusieurs fichiers js en un seul et compressez-les. Raison : À l'heure actuelle, la plupart des navigateurs prennent déjà en charge le téléchargement parallèle de fichiers js, mais il existe toujours une certaine limite sur le nombre de téléchargements simultanés (en fonction du navigateur, certains navigateurs ne peuvent en télécharger que 4), et chaque fichier js doit créer un supplémentaire Avec une connexion http, le chargement de quatre fichiers de 25 Ko prend plus de temps que le chargement d'un fichier de 100 Ko. Par conséquent, notre meilleure option consiste à fusionner plusieurs fichiers js en un seul et à compresser le code.
Lorsqu'une fonction est exécutée, un contexte d'exécution sera généré. Ce contexte d'exécution définit l'environnement dans lequel la fonction est exécutée. Lorsque la fonction termine son exécution, le contexte d'exécution sera détruit. Par conséquent, appeler plusieurs fois la même fonction entraîne la création de plusieurs contextes d’exécution. Chaque contexte d'exécution possède sa propre chaîne de portée. Je pense que tout le monde aurait dû connaître la portée depuis longtemps. Pour une fonction, sa première portée est constituée des variables à l'intérieur de sa fonction. Pendant l'exécution de la fonction, chaque fois qu'une variable est rencontrée, la chaîne de portée de la fonction sera recherchée pour trouver la première variable correspondante. Elle recherche d'abord les variables à l'intérieur de la fonction, puis recherche couche par couche le long de la chaîne de portée. Par conséquent, si nous voulons accéder aux variables les plus externes (variables globales), cela entraînera une perte de performances relativement importante par rapport à l'accès direct aux variables internes. Par conséquent, nous pouvons stocker les références de variables globales fréquemment utilisées dans une variable locale .
const a = 5; function outter () { const a = 2; function inner () { const b = 2; console.log(b); // 2 console.log(a); // 2 } inner(); }
En JavaScript, il en existe principalement quatre types : les littéraux, les variables locales, les éléments de tableau et les objets. L'accès aux littéraux et aux variables locales est le plus rapide, tandis que l'accès aux éléments du tableau et aux membres des objets est relativement lent. Lors de l'accès aux membres d'un objet, tout comme à la chaîne de portée, la recherche est effectuée sur la chaîne prototype (prototype). Par conséquent, si le membre recherché se trouve trop profondément dans la chaîne du prototype, la vitesse d’accès sera plus lente. Par conséquent, nous devrions réduire autant que possible le nombre de recherches et la profondeur d’imbrication des membres de l’objet . Par exemple, le code suivant
// 进行两次对象成员查找 function hasEitherClass(element, className1, className2) { return element.className === className1 || element.className === className2; } // 优化,如果该变量不会改变,则可以使用局部变量保存查找的内容 function hasEitherClass(element, className1, className2) { const currentClassName = element.className; return currentClassName === className1 || currentClassName === className2; }
minimise le nombre d'opérations DOM, utilise JavaScript pour le traiter autant que possible et utilise le code local variables pour le stockage autant que possible du nœud DOM. Par exemple, le code suivant :
// 优化前,在每次循环的时候,都要获取id为t的节点,并且设置它的innerHTML function innerHTMLLoop () { for (let count = 0; count < 15000; count++) { document.getElementById('t').innerHTML += 'a'; } } // 优化后, function innerHTMLLoop () { const tNode = document.getElemenById('t'); const insertHtml = ''; for (let count = 0; count < 15000; count++) { insertHtml += 'a'; } tNode.innerHtml += insertHtml; }
Réduisez la refusion et redessinez autant que possible. La redistribution et le redessinage peuvent être très coûteux, donc afin de réduire. le nombre de réarrangements et de re-fusions, on peut faire les optimisations suivantes
1 Quand on veut modifier le style du Dom, on doit fusionner toutes les modifications autant que possible. possible Et il est traité en une seule fois, réduisant ainsi le nombre de réarrangements et de réenvois.
// 优化前 const el = document.getElementById('test'); el.style.borderLeft = '1px'; el.style.borderRight = '2px'; el.style.padding = '5px'; // 优化后,一次性修改样式,这样可以将三次重排减少到一次重排 const el = document.getElementById('test'); el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'
2.当我们要批量修改DOM节点的时候,我们可以将DOM节点隐藏掉,然后进行一系列的修改操作,之后再将其设置为可见,这样就可以最多只进行两次重排。具体的方法如下:
// 未优化前 const ele = document.getElementById('test'); // 一系列dom修改操作 // 优化方案一,将要修改的节点设置为不显示,之后对它进行修改,修改完成后再显示该节点,从而只需要两次重排 const ele = document.getElementById('test'); ele.style.display = 'none'; // 一系列dom修改操作 ele.style.display = 'block'; // 优化方案二,首先创建一个文档片段(documentFragment),然后对该片段进行修改,之后将文档片段插入到文档中,只有最后将文档片段插入文档的时候会引起重排,因此只会触发一次重排。。 const fragment = document.createDocumentFragment(); const ele = document.getElementById('test'); // 一系列dom修改操作 ele.appendChild(fragment);
3.使用事件委托:事件委托就是将目标节点的事件移到父节点来处理,由于浏览器冒泡的特点,当目标节点触发了该事件的时候,父节点也会触发该事件。因此,由父节点来负责监听和处理该事件。
那么,它的优点在哪里呢?假设你有一个列表,里面每一个列表项都需要绑定相同的事件,而这个列表可能会频繁的插入和删除。如果按照平常的方法,你只能给每一个列表项都绑定一个事件处理器,并且,每当插入新的列表项的时候,你也需要为新的列表项注册新的事件处理器。这样的话,如果列表项很大的话,就会导致有特别多的事件处理器,造成极大的性能问题。而通过事件委托,我们只需要在列表项的父节点监听这个事件,由它来统一处理就可以了。这样,对于新增的列表项也不需要做额外的处理。而且事件委托的用法其实也很简单:
function handleClick(target) { // 点击列表项的处理事件 } function delegate (e) { // 判断目标对象是否为列表项 if (e.target.nodeName === 'LI') { handleClick(e.target); } } const parent = document.getElementById('parent'); parent.addEventListener('click', delegate);
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!