Maison  >  Article  >  interface Web  >  Résumé de l'optimisation des performances frontales Js

Résumé de l'optimisation des performances frontales Js

小云云
小云云original
2018-02-28 13:42:481773parcourir

La meilleure optimisation des ressources est de ne pas charger de ressources. La mise en cache est également la méthode d'optimisation la plus efficace. Pour être honnête, bien que la mise en cache côté client s'effectue du côté du navigateur, la mise en cache est principalement contrôlée par le serveur et n'a pas grand-chose à voir avec notre front-end. Mais encore faut-il comprendre.

La mise en cache inclut la mise en cache côté serveur et la mise en cache côté client. Cet article ne parle que de la mise en cache côté client. Le cache dit client est principalement du cache http. La mise en cache HTTP est principalement divisée en mise en cache forcée et mise en cache négociée.

Mise en cache forcée

  • Expire (http1.0)

Utilisez Expire dans http1.0 pour effectuer une mise en cache forcée. La valeur de Expires est le délai d'expiration des données renvoyées par le serveur. Lorsque le temps de requête lors d'une nouvelle demande est inférieur au temps renvoyé, les données mises en cache seront utilisées directement. Cependant, étant donné que l'heure du serveur et celle du client peuvent être différentes, cela entraînera également des erreurs d'accès au cache.

  • Cache-Control

Cache-Control a de nombreux attributs, et différents attributs ont des significations différentes.

  1. privé : le client peut mettre en cache

  2. public : le client et le serveur proxy peuvent mettre en cache

  3. max-age=t : Le contenu mis en cache expirera après t secondes

  4. no-cache : Nécessité d'utiliser un cache négocié pour vérifier les données mises en cache

  5. no-store : tout le contenu ne sera pas mis en cache.

Négocier le cache

La première fois que le navigateur demande des données, le serveur répondra au client avec l'ID du cache et les données, et le client les sauvegardera dans la cache. Lors d'une nouvelle demande, le client enverra l'identifiant présent dans le cache au serveur, et le serveur jugera en fonction de cet identifiant. S'il n'a pas expiré, un code d'état 304 sera renvoyé. Le navigateur pourra utiliser les données mises en cache directement après avoir reçu ce code d'état.

  • Dernière modification

Lorsque le serveur répond à la demande, il indiquera au navigateur l'heure de la dernière modification de la ressource

  • if-Modified-Since

Lorsque le navigateur demandera à nouveau le serveur, l'en-tête de la requête contiendra ce champ, suivi du Last-Modified (dernier heure de modification) obtenue dans le cache). Lorsque le serveur reçoit cet en-tête de requête et qu'il y a if-Modified-Since, il le compare avec l'heure de dernière modification de la ressource demandée. Si elle est supérieure à l'heure de dernière modification de la ressource demandée, il renvoie 304, et le navigateur. obtient la ressource du cache. Si elle est inférieure à l'heure de la dernière modification de la ressource demandée, 200 est renvoyé et la dernière ressource est renvoyée. Le navigateur obtient la dernière ressource du serveur et la met en cache.

  • Etag

Une chaîne d'identification unique générée par le serveur pour chaque ressource

  • Si - Aucun-Match

Lors d'une nouvelle demande au serveur, l'en-tête du message de demande du navigateur contiendra ce champ et la valeur suivante est l'identifiant obtenu dans le cache. Après avoir reçu le message, le serveur trouve If-None-Match et le compare avec l'identifiant unique de la ressource demandée. S'ils sont identiques, cela signifie que la ressource n'a pas été modifiée, renvoyez 304 et le navigateur obtient la ressource du cache. S'ils sont différents, cela signifie que la ressource a été modifiée, renvoyez 200 et renvoyez le. dernière ressource. Le navigateur obtient la dernière ressource du serveur et la met en cache.

Last-Modified et ETag peuvent être utilisés ensemble. Le serveur vérifiera d'abord l'ETag s'ils sont cohérents, il continuera à comparer Last-Modified et décidera enfin s'il doit renvoyer 304.

Si vous utilisez un outil de packaging frontal, vous pouvez ajouter un numéro de version ou une valeur de hachage au fichier lors du packaging, et vous pouvez également distinguer si la ressource a expiré.

Réduire les requêtes http

  • Utiliser CDN pour héberger des ressources statiques

  • Vous pouvez utiliser des outils d'empaquetage tels que gulp et webpack pour package js et css Attendez que les fichiers soient fusionnés et compressés

  • Les images sont chargées paresseusement et à la demande, et les images ne sont chargées que lors du défilement vers la zone visible de l'image

  • Petites images et images qui ne changeront pratiquement pas sont transmises en utilisant le codage base64. N'abusez pas de base64. Même les petites images généreront de très longues chaînes après l'encodage en base64. Si vous abusez de base64, cela sera contre-productif, car si une image est modifiée, l'image entière du sprite sera régénérée si elle est utilisée. sans discernement, cela sera contre-productif.

  • Réduire la taille des ressources de requête http

Utiliser Webpack, gulp et d'autres outils pour compresser les ressources

  • Activez la compression gzip sur le serveur (le taux de compression est très impressionnant, généralement supérieur à 30%)

  • Si vous utilisez des outils de packaging, l'optimisation du packaging doit être bien faite, ressources publiques , extraction de code tiers, Il n'y a pas besoin de bibliothèques packagées...

  • Optimisation du rendu

  • Ceux qui ont lu le mécanisme d'exécution js précédent doivent savoir que le L'URL est saisie depuis le navigateur vers la page apparaissant à l'écran, ce qui s'est passé (la poignée de main TCP, la résolution DNS, etc. ne sont pas à la portée des connaissances).

FPS 16 ms, moins de 10 ms est le meilleur, utilisez Google devtool pour vérifier la fréquence d'images

Si le FPS du navigateur atteint 60, il apparaîtra plus fluide. La fréquence de rafraîchissement de la plupart des moniteurs est de 60 Hz et le navigateur actualisera automatiquement les animations à cette fréquence.
Calculé sur la base d'un FPS égal à 60, le temps de trame moyen est de 1000 ms/60 = 16,7 ms, donc chaque temps de rendu ne peut pas dépasser 16 ms. S'il dépasse ce temps, une perte de trame et un décalage se produiront.

Vous pouvez vérifier le taux de rafraîchissement dans la chronologie des outils de développement du navigateur Chrome, et vous pouvez vérifier la consommation de temps de toutes les fréquences d'images et l'exécution d'une certaine image. Tutoriel d'utilisation de la timeline : https://segmentfault.com/a/11...

Afin de garantir des FPS normaux, une certaine optimisation des performances de rendu est encore nécessaire. Voici toutes les stratégies liées à l’optimisation du rendu.

  • Essayez d'utiliser CSS3 pour les animations

Comme nous le savons tous, les performances de CSS sont plus rapides que celles de JS, vous pouvez donc utiliser CSS et essayez de ne pas utiliser js Pour implémenter

  • évitez d'utiliser setTimeout ou setInterval, essayez d'utiliser requestAnimationFrame pour l'animation ou les opérations Dom à haute fréquence.

Étant donné que setTimeout et setInterval ne peuvent pas garantir le timing d'exécution de la fonction de rappel, elle est susceptible d'être exécutée à la fin de la trame, entraînant une perte de trame, mais requestAnimationFrame peut garantir que le La fonction de rappel sera exécutée au début de chaque image d'animation lors de l'exécution de
requestAnimationFrame Adresse MDN chinoise : https://developer.mozilla.org...

  • Calcul complexe. les opérations utilisent des Web Workers

Si vous avez besoin d'opérations de données complexes, telles que parcourir et additionner un tableau d'éléments, alors les Web Workers sont parfaits.

Les Web Workers peuvent autoriser l'exécution de scripts JavaScript dans des threads d'arrière-plan (similaires à la création d'un thread enfant), et le thread d'arrière-plan n'affectera pas la page du thread principal. Cependant, les threads créés à l'aide de Web Workers ne peuvent pas exploiter l'arborescence DOM.
Pour plus d'informations sur les Web Workers, vous pouvez consulter l'explication détaillée de MDN : https://developer.mozilla.org...

  • css est placé en tête et js est placé à la queue.

Ceux qui ont lu le mécanisme d'exécution de js précédent devraient connaître le processus de rendu des pages, je n'entrerai donc pas dans les détails. Placer le CSS en tête évitera le phénomène de re-mise en page de l'écran de démarrage après la génération de l'arborescence html js qui a généralement un plus grand impact sur la page et est généralement placé à la fin pour la dernière exécution.

  • Anti-rebond et limitation d'événements

Pour les événements déclenchés à haute fréquence (déplacement de la souris, défilement) et d'autres événements, s'il n'est pas contrôlé, il peut déclencher de nombreux événements dans un court laps de temps.

La fonction anti-shake signifie que lorsqu'il est déclenché fréquemment, le code ne sera exécuté qu'une seule fois s'il y a suffisamment de temps libre. Scénario : Dans la zone de saisie de l'e-mail lors de l'inscription, au fur et à mesure que l'utilisateur saisit, il est jugé en temps réel si le format de l'e-mail est correct. Lorsque le premier événement de saisie est déclenché, définissez le timing : effectuez la vérification après 800 ms. Si seulement 100 ms se sont écoulées et que le dernier minuteur n'a pas été exécuté, effacez le minuteur et resynchronisez-le à 800 ms. Jusqu'à la dernière entrée, il n'y a pas d'entrée adjacente, le timing de cette dernière entrée se termine et le code de contrôle est finalement exécuté.

const filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;  
$("#email").on("keyup",checkEmail());  
function checkEmail(){  
    let timer=null;  
    return function (){  
        clearTimeout(timer);  
        timer=setTimeout(function(){  
            console.log('执行检查');  
        },800);  
    }  
}

La limitation des fonctions signifie que la méthode js ne s'exécute qu'une seule fois au cours d'une certaine période de temps. Autrement dit, ce qui était initialement exécuté 100 fois par seconde devient 10 fois par seconde.
Scénario : le scénario réel de l'application de limitation de fonctions, dont la plupart seront utilisés lors de la surveillance des événements de défilement des éléments de la page.

var canRun = true;
document.getElementById("throttle").onscroll = function(){
    if(!canRun){
        // 判断是否已空闲,如果在执行中,则直接return
        return;
    }

    canRun = false;
    setTimeout(function(){
        console.log("函数节流");
        canRun = true;
    }, 300);
};
  • Opération Dom

Les développeurs front-end savent tous que l'opération Do prend beaucoup de temps (j'en ai personnellement testé 30* 30 parcours de table pour ajouter des styles). Essayez donc d'éviter les opérations Dom fréquentes. Si vous ne pouvez pas l'éviter, essayez d'optimiser les opérations DOm.

1.:缓存Dom查询,比如通过getElementByTagName('p')获取Dom集,而不是逐个获取。

2: 合并Dom操作,使用createDocumentFragment()
    var frag = document.createDocumentFragment()
    for (i<10) {
        var li = document.createElement(&#39;li&#39;)
        frag.appendChild(li)
    }
    document.body.appendChild(frag)
 3: 使用React、Vue等框架的虚拟dom(原理目前还不明白),可以更快的实现dom操作。
  • Essayez d'éviter de repeindre et de refusionner

Si vous utilisez js pour modifier des éléments La couleur ou l'arrière-plan La couleur déclenchera le redessin, et le coût du redessin est encore relativement élevé, car le navigateur vérifiera tous les nœuds d'un élément DOM après que l'effet visuel des changements d'élément DOM.

Si la taille et la position de l'élément sont modifiées, une redistribution se produira. La redistribution est plus coûteuse. Elle sera déclenchée après le changement de la position d'un certain élément DOM, et elle recalculera la position de tous les éléments et. leur placement sur la page. La zone occupée entraînera le rendu d'une certaine partie de la page, voire de la page entière.

  • Accélération matérielle CSS3

Lors du rendu du navigateur, il sera divisé en deux couches : une couche normale et une couche composite.

Le flux de documents ordinaire peut être compris comme une couche composite. Bien que la mise en page absolue et fixe puisse être séparée du flux de documents ordinaire, elle appartient toujours à la couche ordinaire et l'accélération matérielle ne sera pas activée. La repeinture et la refusion mentionnées ci-dessus font référence au redessin et à la refusion sur des calques ordinaires.

Les couches composées permettront l’accélération matérielle. Il ne se trouve pas dans le même calque que le calque ordinaire, donc le calque composite n'affectera pas le calque ordinaire. Si un élément est promu au calque composite, puis que l'élément est exploité, cela n'entraînera pas le redessin du calque ordinaire. et redistribué. Cela améliore les performances de rendu.

Comment démarrer l'accélération matérielle :

1. Utilisez Translate3d et TranslateZ

.
webkit-transform: translateZ(0);
-moz-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);

webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);

2.使用opacity
需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态

3.使用will-chang属性
这个属性比较不常用,一般配合opacity与translate使用

针对webkit浏览器,启用硬件加速有些时候可能会导致浏览器频繁闪烁或抖动,可以使用下面方法消除:

-webkit-backface-visibility:hidden;
-webkit-perspective:1000;
如果使用硬件加速,请使用z-index配合使用, 因为如果这个元素添加了硬件加速,并且index层级比较低, 那么在这个元素的后面其它元素(层级比这个元素高的,或者相同的,并且releative或absolute属性相同的), 会默认变为复合层渲染,如果处理不当会极大的影响性能
  • 避免强制同步布局和布局抖动

浏览器渲染过程为:js/css(javascript) > 计算样式(style) > 布局(layout) > 绘制(paint) > 渲染合并图层(Composite)

JavaScript:JavaScript实现动画效果,DOM元素操作等。
Style(计算样式):确定每个DOM元素应该应用什么CSS规则。
Layout(布局):计算每个DOM元素在最终屏幕上显示的大小和位置。
Paint(绘制):在多个层上绘制DOM元素的的文字、颜色、图像、边框和阴影等。
Composite(渲染层合并):按照合理的顺序合并图层然后显示到屏幕上。

在js中如果读取style属性的某些值就会让浏览器强行进行一次布局、计算,然后再返回值,比如:

offsetTop, offsetLeft, offsetWidth, offsetHeight

scrollTop/Left/Width/Height

clientTop/Left/Width/Height

width,height

请求了getComputedStyle(), 或者 IE的 currentStyle

所以,如果强制浏览器在执行JavaScript脚本之前先执行布局过程,这就是所谓的强制同步布局。
比如下面代码:

requestAnimationFrame(logBoxHeight);

// 先写后读,触发强制布局
function logBoxHeight() {
    // 更新box样式
    box.classList.add('super-big');

    // 为了返回box的offersetHeight值
    // 浏览器必须先应用属性修改,接着执行布局过程
    console.log(box.offsetHeight);
}

// 先读后写,避免强制布局
function logBoxHeight() {
    // 获取box.offsetHeight
    console.log(box.offsetHeight);

    // 更新box样式
    box.classList.add('super-big');
}

在JavaScript脚本运行的时候,它能获取到的元素样式属性值都是上一帧画面的,都是旧的值。因此,如果你在当前帧获取属性之前又对元素节点有改动,那就会导致浏览器必须先应用属性修改,结果执行布局过程,最后再执行JavaScript逻辑。

如果连续多次强制同步布局,就会导致布局抖动
比如下面代码:

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = box.offsetWidth + &#39;px&#39;;
  }
}

作者:SylvanasSun
链接:https://juejin.im/post/59da456951882525ed2b706d
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们知道浏览器是一帧一帧的刷新页面的,对于每一帧,上一帧的布局信息都是已知的。
强制布局就是使用js强制浏览器提前布局,比如下面代码:

// bed  每次循环都要去获取left ,就会发生一次回流
function logBoxHeight() {
  box.style.left += 10
  console.log(box.style.left)
}

// goog 
var width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = width + &#39;px&#39;;
  }
}
  • DOMContentLoaded与Load

DOMContentLoaded 事件触发时,仅当DOM加载完成才触发DOMContentLoaded,此时样式表,图片,外部引入资源都还没加载。而load是等所有的资源加载完毕才会触发。

1. 解析HTML结构。
2. 加载外部脚本和样式表文件。
3. 解析并执行脚本代码。
4. DOM树构建完成。//DOMContentLoaded
5. 加载图片等外部文件。
页面加载完毕。//load
  • 视觉优化

等待加载时间可以合理使用loading gif动图一定程度上消除用户等待时间的烦躁感

代码性能

代码对性能的影响可大可小,但是养成一个良好的写代码习惯和高质量的代码,会潜移默化的提高性能,同时也能提高自己的水平。废话不多说,直接看我总结的部分要点(因为这一部分知识点太多,需要大家写代码的时候多多总结)。

  • 避免全局查找

访问局部变量会比访问全局变量快,因为js查找变量的时候现在局部作用局查找,找不到在逐级向上找。

// bad
function f () {
    for (...){
        console.log(window.location.href)
    }
}

//good
function f () {
    var href = window.location.href
    for (...){
        console.log(href)
    }
}
  • 循环技巧

// bed 
for(var i = 0; i < array.length; i++){
    ....
}
// good
for(var i = 0, len = array.length; i < len; i++){
    ....
}
// 不用每次查询长度
  • 不要使用for in 遍历数组

for in是最慢的,其他的都差不多,其中直接使用for循环是最快的。for in只是适合用来遍历对象。

  • 使用+''代替String()吧变量转化为字符串

var a = 12
//bad
a = String(a)

// good
var a = 12
a = a + &#39;&#39;

这个还有很多类似的,比如使用*1代替parseInt()等都是利用js的弱类型,其实这样对性能提升不是很大,网上有人测试过,进行十几万次变量转换,才快了零点几秒。

  • 删除dom

删除dom元素要删除注册在该节点上的事件,否则就会产生无法回收的内存,在选择removeChild和innerHTML=''二者之间尽量选择后者,据说removeChild有时候无法有效的释放节点(具体原因不明)

  • 使用事件代理处理事件

任何可以冒泡的事件都可以在节点的祖先节点上处理,这样对于子节点需要绑定相同事件的情况就不用分别给每个子节点添加事件监听,而是都提升到祖先节点处理。

  • 通过js生成的dom对象必须append到页面中

在IE下,js创建的额dom如果没有添加到页面,这部分内存是不会被回收的

  • 避免与null比较

可以使用下面方法替换与null比较
1.如果该值为引用类型,则使用instanceof检查其构造函数
2.如果该值为基本类型,使用typeof检查类型

  • 尽量使用三目运算符代替if else

if(a>b){num = a}
else{num = b}

// 可以替换为
num = a > b ? a : b
  • 当判断条件大于3中情况时,使用switch代替if

因为switch的执行速度比if要快,也别是在IE下,速度大约是if的两倍。

相关推荐:

CSS解读前端性能优化的具体分析

在HTML5中如何提高网站前端性能的示例代码分析

web前端性能优化方法


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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn