搜索
首页web前端js教程Js前端性能优化总结

Js前端性能优化总结

Feb 28, 2018 pm 01:42 PM
javascript优化总结

最好的资源优化就是不加载资源。缓存也是最见效的优化手段。说实话,虽然说客户端缓存发生在浏览器端,但缓存主要还是服务端来控制,与我们前端关系并不是很大。但还是有必要了解一下。

缓存包括服务端缓存和客户端缓存,本文只谈客户端缓存。所谓客户端缓存主要是http缓存。http缓存主要分为强制缓存和协商缓存。

强制缓存

  • Expires(http1.0)

在http1.0中使用Expires来做强制缓存。Exprires的值为服务端返回的数据到期时间。当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据。但由于服务端时间和客户端时间可能有误差,这也将导致缓存命中的误差。

  • Cache-Control

Cache-Control有很多属性,不同的属性代表的意义也不同。

  1. private:客户端可以缓存

  2. public:客户端和代理服务器都可以缓存

  3. max-age=t:缓存内容将在t秒后失效

  4. no-cache:需要使用协商缓存来验证缓存数据

  5. no-store:所有内容都不会缓存。

协商缓存

浏览器第一次请求数据时,服务器会将缓存标识与数据一起响应给客户端,客户端将它们备份至缓存中。再次请求时,客户端会将缓存中的标识发送给服务器,服务器根据此标识判断。若未失效,返回304状态码,浏览器拿到此状态码就可以直接使用缓存数据了。

  • Last-Modified

服务器在响应请求时,会告诉浏览器资源的最后修改时间

  • if-Modified-Since

浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获得的Last-Modified(最后修改时间)。服务端收到此请求头发现有if-Modified-Since,则与被请求资源的最后修改时间进行对比,如果大于被请求资源最后修改时间则返回304,浏览器从缓存获取资源。如果小于被请求资源最后修改时间,则返回200,并返回最新资源,浏览器从服务端获取最新的资源,并缓存。

  • Etag

由服务器生成的每个资源的唯一标识字符串

  • If-None-Match

再次请求服务器时,浏览器的请求报文头部会包含此字段,后面的值为在缓存中获取的标识。服务器接收到次报文后发现If-None-Match则与被请求资源的唯一标识进行对比。如果相同,说明资源没有被修改过,返回304,浏览器从缓存获取资源,如果不同说明资源被修改过,则返回200,并返回最新资源,浏览器从服务端获取最新资源,并缓存。

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

如果使用前端打包工具,可以在打包文件时候在给文件添加版本号或者hash值,同样可以区分资源是否过期。

减少http请求

  • 使用CDN托管静态资源

  • 可以借助gulp、webpack等打包工具对js、css等文件合并与压缩

  • 图片懒加载、按需加载,当滚动到图片可视区域才去加载图片

  • 小图片并且基本不会改动的图片使用base64编码传输。base64不要滥用,即使小图片经过base64编码之后也会生成很长的字符串,如果滥用base64反而会适得其反

  • 雪碧图,这个也是针对基本不会更改的图片才使用雪碧图,因为如果一张图片修改,会导致整个雪碧图重新生成,如果乱用也会适得其反。

减小http请求资源体积

  • 借助webpack、gulp等工具压缩资源

  • 服务端开启gzip压缩(压缩率非常可观,一般都在30%之上)

  • 如果有用打包工具,打包优化要做好,公共资源、提取第三方代码、不需要打包的库...

渲染优化

读过前面js运行机制的应该知道,从浏览器输入url,到页面出现在屏幕上,都发生了哪些事(tcp握手、dns解析等不在认知范围)。
  • FPS 16ms 小于10ms完成最好  Google devtool 查看帧率

如果浏览器FPS到达60,就会显得比较流畅,大多数显示器的刷新频率是60Hz,浏览器会自动按照这个频率刷新动画。
按照FPS等于60来计算,平均一帧的时间为1000ms/60 = 16.7ms,所以每次渲染时间不能超过16ms,如果超过这个时间就会出现丢帧、卡顿现象。

可以在chrome浏览器开发者工具中的Timeline中查看刷新率,可以查看所有帧率耗时情况以及某一帧的执行情况。Timeline的使用教程:https://segmentfault.com/a/11...

为了保证正常的FPS,有些渲染性能优化还是有必要的。下面所介绍的都是有关渲染优化的策略。

  • 尽量使用css3来做动画

总所周知,css的性能要比js快,所以能使用css,尽量不用js来实现

  • 避免使用setTimeout或setInterval,尽量使用requestAnimationFrame来做动画或者高频Dom操作。

因为setTimeout和setInterval无法保证callback函数的执行时机,很可能在帧结束的时候执行,从而导致丢帧,但是requestAnimationFrame可以保证callback函数在每帧动画开始的时候执行
requestAnimationFrame的中文MDN地址:https://developer.mozilla.org...

  • 复杂的计算操作使用Web Workers

如果有需要复杂的数据操作,比如对一个有一个个元素的数组遍历求和,那么Web Workers在适合不过了。

Web Workers可以让JavaScript脚本运行在后台线程(类似于创建一个子线程),而后台线程不会影响到主线程中的页面。不过,使用Web Workers创建的线程是不能操作DOM树。
有关Web Workers的更多可以查看MDN详解:https://developer.mozilla.org...

  • css放在头部,js放在尾部。

读过前面js运行机制的应该知道页面渲染是怎样一个过程,不再赘述了。css放在头部会避免生成html树之后重新布局的闪屏现象,js一般对页面的影响较大,一般放在尾部最后执行。

  • 事件防抖(debounce)与节流(throttle)

针对高频触发的事件(mousemove、scroll)等事件,如果不加以控制会在短时间内触发很多事件。

函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。场景:注册时邮箱的输入框,随着用户的输入,实时判断邮箱格式是否正确,当第一次输入事件触发,设置定时:在800ms之后执行检查。假如只过了100ms,上次的定时还没执行,此时清除定时,重新定时800ms。直到最近一次的输入,后面没有紧邻的输入了,这最近一次的输入定时计时结束,终于执行了检查代码。

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);  
    }  
}

函数节流是指一定时间内js方法只跑一次。就是本来一秒要执行100次的变成一秒执行10次。
场景:函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。

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

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

前端开发人员都知道Do操作是非常耗时的(曾亲测过30*30的表格遍历添加样式)。所以尽量避免频繁的Dom操作,如果避免不了就尽量对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操作。
  • 尽量避免重绘(rePaint)和回流(reFlow)

如果使用js修改元素的颜色或者背景色就会触发重绘,重绘的开销还是比较昂贵的,因为浏览器会在某一个DOM元素的视觉效果改变后去check这个DOM元素内的所有节点。

如果修改元素的尺寸和位置就会发生回流,回流开销更大,它会在某一个DOM元素的位置发生改变后触发,而且它会重新计算所有元素的位置和在页面中的占有的面积,这样的话将会引起页面某一个部分甚至整个页面的重新渲染。

  • css3硬件加速

浏览器渲染时,会分为两个图层:普通图层和复合图层。

普通文档流内可以理解为一个复合图层,absolute、fixed布局虽然可以脱离普通文档流,但它仍然属于普通图层,不会启动硬件加速。上面说的重绘(rePaint)和回流(reFlow)说的就是普通图层上的重绘和回流。

复合图层会启动硬件加速。和普通图层不在同一个图层,所以复合图层不会影响普通图层,如果一个元素被提升到复合图层,再操作该元素时,就不会引起普通图层的重绘和回流,从而提升渲染性能。

如何启动硬件加速:

1.使用translate3d和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前端性能优化方法


以上是Js前端性能优化总结的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript是用C编写的吗?检查证据JavaScript是用C编写的吗?检查证据Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C语言编写的。1)C语言提供了高效性能和底层控制,适合JavaScript引擎的开发。2)以V8引擎为例,其核心用C 编写,结合了C的效率和面向对象特性。3)JavaScript引擎的工作原理包括解析、编译和执行,C语言在这些过程中发挥关键作用。

JavaScript的角色:使网络交互和动态JavaScript的角色:使网络交互和动态Apr 24, 2025 am 12:12 AM

JavaScript是现代网站的核心,因为它增强了网页的交互性和动态性。1)它允许在不刷新页面的情况下改变内容,2)通过DOMAPI操作网页,3)支持复杂的交互效果如动画和拖放,4)优化性能和最佳实践提高用户体验。

C和JavaScript:连接解释C和JavaScript:连接解释Apr 23, 2025 am 12:07 AM

C 和JavaScript通过WebAssembly实现互操作性。1)C 代码编译成WebAssembly模块,引入到JavaScript环境中,增强计算能力。2)在游戏开发中,C 处理物理引擎和图形渲染,JavaScript负责游戏逻辑和用户界面。

从网站到应用程序:JavaScript的不同应用从网站到应用程序:JavaScript的不同应用Apr 22, 2025 am 12:02 AM

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python vs. JavaScript:比较用例和应用程序Python vs. JavaScript:比较用例和应用程序Apr 21, 2025 am 12:01 AM

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C/C在JavaScript口译员和编译器中的作用C/C在JavaScript口译员和编译器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在行动中:现实世界中的示例和项目JavaScript在行动中:现实世界中的示例和项目Apr 19, 2025 am 12:13 AM

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中