浏览器衬着道理
浏览器衬着流程
JavaScript
JavaScript完成动画结果,DOM元素操纵等。
CSSOM
肯定每一个DOM元素应当运用什么CSS划定规矩。
注重: CSS选择器越细致,婚配事情越多,婚配节点越慢。
RenderTree(衬着树)
RenderTree包含了衬着网页所需的节点, 无需衬着的节点不会被增加到RenderTree中。 如:<head>,display: none的节点
注重:因为设置了visibility:hidden的元素虽不可见,但仍然占领空间,仍会被增加到RenderTree。
Layout(规划)
盘算每一个DOM元素在终究屏幕上显现的大小和位置。因为web页面的元素规划是相对的,所以个中恣意一个元素的位置发作变化,都邑联动的引发其他元素发作变化,这个历程叫reflow。
注重:影响web机能的一个主要的题目就是repaint和reflow。
触发Layout
屏幕扭转
浏览器视窗转变
与大小位置相干的CSS属性转变
Paint(绘制)
依据background,border,box-shadow等款式,将Layout天生的地区添补为终究将显现在屏幕上的像素
Composite(衬着层兼并)
根据合理的递次兼并图层然后显现到屏幕上。
三种衬着流程
现实场景下,也许会有三种罕见的衬着流程:
JavaScript -> CSS -> Layout -> Paint -> Composite
JavaScript -> CSS -> Paint -> Composite
JavaScript -> CSS -> Composite
注重:Layout和Paint步骤是可防备的
优化CSS
浏览器会在DOM和CSSOM加载完最先衬着页面。
防备CSS壅塞首次衬着
<style>/* styles here */</style>
<link rel="stylesheet" href="index.css">
经由过程以上两种体式格局定义的CSS,均会壅塞首次衬着。浏览器会在剖析完CSS后,再举行衬着。这是为了防备款式突变带来的发抖。经由过程link标签引入的CSS壅塞的时刻能够更长,因为加载它须要一个收集往返时刻
media query
<link rel="stylesheet" href="index_print.css" media="print">
此款式表仍会加载。当浏览器环境不婚配媒体查询前提时,该款式表不会壅塞衬着。我们可针对差别媒体环境拆分CSS文件,并为link标签增加媒体查询,防备为了加载非症结CSS资本,而壅塞首次衬着
经由过程DOM API增加link
var style = document.createElement('link');
style.rel = 'stylesheet';
style.href = 'index.css';
document.head.appendChild(style);
该要领不会壅塞首次衬着。
preload
<link rel="preload" href="index_print.css" as="style" onload="this.rel='stylesheet'">
rel不是stylesheet,因而不会壅塞衬着。preload是resoure hint范例中定义的一个功用,resource hint经由过程示知浏览器提早竖立衔接或加载资本,以进步资本加载的速率。浏览器碰到碰到标记为preload的link时,会最先加载,当onload事宜发作时,将rel改成stylesheet,即可运用此款式。
总结
引入CSS资本的要领 | 是不是壅塞首次衬着 |
---|---|
<link rel=”stylesheet” href=”index.css” /> | 是 |
经由过程document.write写入以上标签 | 是 |
经由过程DOM API插进去HTMLLinkElement对象 | 否 |
运用preload体式格局载入CSS | 否 |
为link增加media query | 当媒体查询不婚配时,不会壅塞 |
削减须要实行款式盘算的元素个数
因为浏览器的优化,当代浏览器的款式盘算直接对目的元素实行,而不是对全部页面实行,所以我们应当只管削减须要实行款式盘算的元素的个数。
JavaScript优化
防备Javascript壅塞HTML Parser(剖析器)
<-- inline js -->
<script>/* app logics here */</script>
<-- external js -->
<script src="somescript.js"></script>
经由过程以上两种体式格局引入js均会壅塞HTML parser,因而会壅塞涌现在剧本背面的HTML标记的衬着。而外部script壅塞的时刻平常更长,因为能够包含了一个收集往返时刻。
Javascript能够经由过程document.write修正HTML文档流,因而在实行js时,浏览器会停息剖析DOM的事情。
CSS壅塞JS
<-- inline js -->
<script>/* app logics here */</script>
<-- external js -->
<script src="somescript.js"></script>
经由过程以上两种体式格局引入的JS均会被CSS壅塞,因为这些Javascript能够会读取或修正CSSOM,因而需守候CSSOM组织完成后,它们才实行
将资本放到文档底部,耽误js实行
<html>
<head></head>
<body>
<h1>世界上最优美的言语是什么?</h1>
<button>See answer</button>
<!-- index.js内容:
为button标签增加点击事宜,点击后,alert答案
-->
<script src="index.js"></script>
<!-- 百度统计代码 -->
<script src="tongji.js"></script>
</body>
</html>
运用defer耽误剧本实行
<html>
<head>
<!-- index.js内容:
为button标签增加点击事宜,点击后,alert答案
-->
<script src="index.js" defer></script>
<!-- 百度统计代码 -->
<script src="tongji.js" defer></script>
</head>
<body>
<h1>世界上最优美的言语是什么?</h1>
<button>See answer</button>
</body>
</html>
当script标签具有defer属性时,该剧本会被推晚到全部HTML文档剖析完后,再最先实行。被defer的剧本,在实行时会严厉根据在HTML文档中涌现的递次实行
注重: 运用defer时,浏览器会保证剧本根据在文档中涌现的递次实行
运用async异步加载剧本
<html>
<head>
<!-- index.js内容:
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('p').onclick=function() {
alert('surprise')
}
});
-->
<script src="index.js" async></script>
<!-- 百度统计代码 -->
<script src="tongji.js" async></script>
</head>
<body>
<p>Hello World</p>
</body>
</html>
当script标签具有async属性时,该剧本不会再壅塞HTML parser。且不会被CSS壅塞。
剧本只需加载完成,便可最先实行。
被async的剧本,在实行时会不会严厉根据在HTML文档中涌现的递次实行
async适用于无依靠的自力资本
总结
引入JS资本的要领 | 是不是壅塞文档内容首次衬着 |
---|---|
在head中引入外部剧本<script src="index.js"></script> 或内联剧本<script>/* app logics */</script> | 是 |
将剧本放到body底部 | 否 |
为剧本增加defer属性 | 否 |
为剧本增加async属性 | 否 |
用requestAnimationFrame替换setTimeout或setInterval
setTimeout(callback)和setInterval(callback)没法保证callback函数的实行机遇,很能够在帧完毕的时刻实行,从而致使丢帧。requestAnimationFrame(callback)能够保证callback函数在每帧动画最先的时刻实行。
帧丧失
用Web Worker去处置惩罚耗时的JS代码
JavaScript代码运转在浏览器的主线程上,与此同时,浏览器的主线程还担任款式盘算、规划、绘制的事情,假如JavaScript代码运转时刻太长,就会壅塞其他衬着事情,很能够会致使丢帧。
每帧的衬着应当在16ms内完成,但在动画历程当中,因为已被占用了不少时刻,所以JavaScript代码运转耗时应当控制在3-4毫秒。
假如真的有迥殊耗时且不操纵DOM元素的纯盘算事情,能够斟酌放到Web Workers中实行。
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// 主线程不受Web Workers线程滋扰
dataSortWorker.addEventListener('message', function(evt) {
var sortedData = e.data;
// Web Workers线程实行完毕
// ...
});
用多个frame去处置惩罚DOM元素的更新
因为Web Workers不能操纵DOM元素的限定,所以只能做一些纯盘算的事情,关于许多须要操纵DOM元素的逻辑,能够斟酌分步处置惩罚,把使命分为若干个小使命,每一个使命都放到requestAnimationFrame中回调实行。
var taskList = breakBigTaskIntoMicroTasks(monsterTaskList);
requestAnimationFrame(processTaskList);
function processTaskList(taskStartTime) {
var nextTask = taskList.pop();
// 实行小使命
processTask(nextTask);
if (taskList.length > 0) {
requestAnimationFrame(processTaskList);
}
}
Layout优化
防备触发规划
当修正了元素的属性以后,浏览器将会搜检为了使这个修正见效是不是须要从新盘算规划以及更新衬着树,关于DOM元素的“多少属性”修正,比方width/height/left/top等,都须要从新盘算规划。
运用flexbox替换老的规划模子
老的规划模子以相对/相对/浮动的体式格局将元素定位到屏幕上。Floxbox规划模子用流式规划的体式格局将元素定位到屏幕上。
经由过程一个小试验能够看出两种规划模子的机能差异,一样对1300个元素规划,浮动规划耗时14.3ms,Flexbox规划耗时3.5ms
其他优化
Font
Font壅塞内容衬着
浏览器为了防备FOUT(Flash Of Unstyled Text),会只管守候字体加载完成后,再显现运用了该字体的内容
只有当字体凌驾一段时刻仍未加载胜利时,浏览器才会降级运用体系字体。每一个浏览器都划定了本身的超时时刻
但这也带来了FOIT(Flash Of Invisible Text)题目。内容没法尽快地被展现,致使空缺。