The best resource optimization is not to load resources. Caching is also the most effective optimization method. To be honest, although client-side caching occurs on the browser side, caching is mainly controlled by the server and has little to do with our front-end. But it is still necessary to understand.
Caching includes server-side caching and client-side caching. This article only talks about client-side caching. The so-called client cache is mainly http cache. HTTP caching is mainly divided into forced caching and negotiated caching.
Expires (http1.0)
Use Expires in http1.0 to do forced caching. The value of Exprires is the expiration time of the data returned by the server. When the request time when requesting again is less than the returned time, the cached data will be used directly. However, since the server time and client time may be different, this will also lead to cache hit errors.
Cache-Control
Cache-Control has many attributes, and different attributes have different meanings.
private: The client can cache
public: Both the client and the proxy server can cache
max-age=t: cached content will expire after t seconds
no-cache: Negotiation cache is required to verify cached data
no-store: All content will not be cached.
When the browser requests data for the first time, the server will respond to the client with the cache ID and data, and the client will back them up in the cache. . When requesting again, the client will send the identifier in the cache to the server, and the server will judge based on this identifier. If it has not expired, a 304 status code will be returned. The browser can use the cached data directly after receiving this status code.
Last-Modified
When the server responds to the request, it will tell the browser the last modification time of the resource
if-Modified-Since
When the browser requests the server again, the request header will contain this field, followed by the Last-Modified (last modification time) obtained in the cache ). When the server receives this request header and contains if-Modified-Since, it compares it with the last modification time of the requested resource. If it is greater than the last modification time of the requested resource, it returns 304, and the browser obtains the resource from the cache. If it is less than the last modification time of the requested resource, 200 is returned and the latest resource is returned. The browser obtains the latest resource from the server and caches it.
Etag
A unique identifying string generated by the server for each resource
If -None-Match
When requesting the server again, the browser's request message header will contain this field, and the subsequent value is the identifier obtained in the cache. After receiving the message, the server finds If-None-Match and compares it with the unique identifier of the requested resource. If they are the same, it means that the resource has not been modified, return 304, and the browser obtains the resource from the cache. If they are different, it means that the resource has been modified, then return 200, and return the latest resource. The browser obtains the latest resource from the server and caches it.
Last-Modified and ETag can be used together. The server will verify the ETag first. If they are consistent, it will continue to compare Last-Modified and finally decide whether to return 304.
If you use a front-end packaging tool, you can add a version number or hash value to the file when packaging the file, and you can also distinguish whether the resource has expired.
Use CDN to host static resources
If the browser FPS reaches 60, it will appear smoother. The refresh frequency of most monitors is 60Hz, and the browser will automatically refresh animations at this frequency.
Calculated based on FPS equal to 60, the average frame time is 1000ms/60 = 16.7ms, so each rendering time cannot exceed 16ms. If this time is exceeded, frame loss and lag will occur.
You can check the refresh rate in Timeline in the Chrome browser developer tools, and you can check the time consumption of all frame rates and the execution status of a certain frame. Timeline usage tutorial: https://segmentfault.com/a/11...
In order to ensure normal FPS, some rendering performance optimization is still necessary. The following are all strategies related to rendering optimization.
Try to use css3 for animation
As we all know, the performance of css is faster than js, so you can use css and try not to use js To achieve
avoid using setTimeout or setInterval, try to use requestAnimationFrame for animation or high-frequency Dom operations.
Because setTimeout and setInterval cannot guarantee the execution timing of the callback function, it is likely to be executed at the end of the frame, resulting in frame loss, but requestAnimationFrame can guarantee that the callback function will be executed at the beginning of each frame of animation. When executing
requestAnimationFrame Chinese MDN address: https://developer.mozilla.org...
Complex calculation operations use Web Workers
If you need complex data operations, such as traversing and summing an array of elements, then Web Workers are perfect.
Web Workers can allow JavaScript scripts to run in background threads (similar to creating a child thread), and the background thread will not affect the page in the main thread. However, threads created using Web Workers cannot operate the DOM tree.
For more information about Web Workers, you can view the MDN detailed explanation: https://developer.mozilla.org...
css is placed at the head and js is placed at the tail.
Those who have read the previous js running mechanism should know the process of page rendering, so I won’t go into details. Placing css at the head will avoid the splash screen phenomenon caused by re-layout after generating the html tree. js generally has a greater impact on the page and is generally placed at the end for last execution.
Event debounce and throttling
For high-frequency triggered events (mousemove, scroll) and other events, If not controlled it can trigger many events in a short period of time.
Function anti-shake means that when triggered frequently, the code will only be executed once if there is enough free time. Scenario: In the email input box during registration, as the user inputs, it is judged in real time whether the email format is correct. When the first input event is triggered, set the timing: perform the check after 800ms. If only 100ms has passed and the last timer has not been executed, clear the timer and retime it to 800ms. Until the latest input, there is no adjacent input, the timing of this latest input ends, and the check code is finally executed.
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); } }
Function throttling means that the js method only runs once within a certain period of time. That is, what was originally executed 100 times per second becomes 10 times per second.
Scenario: The actual scenario of function throttling application, most of which will be used when listening to scrolling events of page elements.
var canRun = true; document.getElementById("throttle").onscroll = function(){ if(!canRun){ // 判断是否已空闲,如果在执行中,则直接return return; } canRun = false; setTimeout(function(){ console.log("函数节流"); canRun = true; }, 300); };
Dom operation
Front-end developers all know that Do operation is very time-consuming (I have personally tested a 30*30 table traversal add style). So try to avoid frequent Dom operations. If you can't avoid it, try to optimize the DOm operations.
1.:缓存Dom查询,比如通过getElementByTagName('p')获取Dom集,而不是逐个获取。 2: 合并Dom操作,使用createDocumentFragment()
var frag = document.createDocumentFragment() for (i<10) { var li = document.createElement('li') frag.appendChild(li) } document.body.appendChild(frag)
3: 使用React、Vue等框架的虚拟dom(原理目前还不明白),可以更快的实现dom操作。
Try to avoid repaint (rePaint) and reflow (reFlow)
It will be triggered if you use js to modify the color or background color of the element Redrawing is relatively expensive because the browser will check all nodes within a DOM element after the visual effect of the DOM element changes.
If you modify the size and position of the element, reflow will occur. Reflow is more expensive. It will be triggered after the position of a certain DOM element changes, and it will recalculate the position of all elements and the content on the page. The occupied area will cause a certain part of the page or even the entire page to be re-rendered.
css3 hardware acceleration
When the browser renders, it will be divided into two layers: ordinary layers and composite layers.
The ordinary document flow can be understood as a composite layer. Although the absolute and fixed layout can be separated from the ordinary document flow, it still belongs to the ordinary layer and hardware acceleration will not be activated. The repaint and reflow mentioned above refer to redraw and reflow on ordinary layers.
Composite layers will enable hardware acceleration. It is not in the same layer as the ordinary layer, so the composite layer will not affect the ordinary layer. If an element is promoted to the composite layer, and then the element is operated, it will not cause the ordinary layer to be redrawn and reflowed. This improves rendering performance.
How to start hardware acceleration:
1. Use translate3d and 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 + 'px'; } } 作者: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 + 'px'; } }
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 + ''
这个还有很多类似的,比如使用*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的两倍。
相关推荐:
The above is the detailed content of Summary of Js front-end performance optimization. For more information, please follow other related articles on the PHP Chinese website!