衣食父母-浏览器
我觉得文章题目起的挺现实,在BS大行其道的今天,浏览器作为一款window软件已经是很多程序员兄弟的衣食父母,所以了解一下浏览器是很必要的。
1、背景
作为前端程序员一定要好奇从地址栏输入地址后到底发生了什么
主流浏览器
IE、Firefox、Safari、Chrome、Opera五大家族, Firefox、Chrome是开源的完全开源的,safari部分开源
浏览器的主要构成
用户界面、浏览器引擎、渲染引擎、网络、js解释器、UI后端、数据存储,google为每个tab页分一个渲染引擎,
注:浏览器引擎和渲染引擎的区别
(1) 浏览器引擎是一个主进程、用来管理渲染引擎所在的进程,渲染引擎对应的进程可能只属于一个tab页(chrome),而浏览器进程属于整个浏览器
(2) 渲染引擎没有访问操作系统的权限(文件、网络、设备)而浏览器引擎有,这样的目的是有恶意网站时不会损害整个浏览器或者操作系统
(3) 当用户在地址栏输入网址请求网页时,渲染引擎向浏览器引擎发出请求:依次调用网络获取资源,请求的资源到达后,浏览器引擎把资源传给渲染
渲染引擎,渲染引擎将获取的资源进行解析(html css js),有一些组件(布局进程就属于其中的某个组件)格式化后传给浏览器引擎,浏览器在界面中将界面呈现出来
渲染引擎
渲染引擎有两种Mozilla和webkit,熟悉css的同学可能感觉这俩外国字挺熟悉,对啊css兼容性的属性都会加这俩前缀,渲染引擎就是将请求的资源在浏览器中呈现出来
渲染主流程
首先是获取请求的文档,文档由8kb的数据块构成,8kb的大小是由tcp缺省缓冲区的大小决定的。构建成dom树->构建render树->布局render树->绘制render树。
(1) 渲染引擎从浏览器引擎获取html文档后开始解析,进行词法分析(将输入分成可以理解的单词)和语法分析(对应语言的语义规则,描述文档内容),最终根据文档标签构建一棵DOM树(可以理解成c++的一种数据结构),解析过程如果碰到了行内、内联、外联的css,对应的子进程着手cssom树的构建(可以理解成c++的一种数据结构,描述样式规则),由于是两个进程所以没有阻塞的问题,如果解析过程中碰到了javascript,那么DOM,并且javascript的执行需要等到cssom构建完毕,下一步构建渲染树是需要两个树都是在完成构建的状态。
(2) 此时要构建渲染树了,先从DOM树的根节点开始逐层遍历,然后依次在cssom中找到对应的样式并合并到渲染树,如果碰到了隐藏样式那么
直接在渲染树种忽略。
(3) 对渲染树进行'布局',之前的所有操作都没涉及浏览器窗口,他们就是在这个阶段联系起来的,这样渲染树才能适应不同大小的窗口,这时所有的位置和尺寸都被转换为像素(px)
(4) 最后是将布局树转换格式传给浏览器引擎,在浏览器窗口绘制。
2、css阻塞
从上文中我们知道css是阻塞的也是非阻塞的,阻塞渲染树的构建,但是对于dom树的构建是不阻塞的。如果在构建渲染树时是不阻塞的会发生什么,我们会看到'纯html'没有任何样式,这样是不友好的,但是某些时候我们确实想让它是不阻塞的,比如涉及打印的样式,在特定大屏上的样式,因为他们对渲染的影响比较小,此时可以采用媒体属性(media)
<link href="style.css" rel="stylesheet"> <link href="print.css" rel="stylesheet" media="print"> <link href="style.css" rel="stylesheet" media="all"> <link href="portrait.css" rel="stylesheet" media="orientation:portrait"> <link href="other.css" rel="stylesheet" media="(min-width: 40em)">
注: 不阻塞不是不下载,只是在首次合成渲染树时不受它的阻塞
3、javascript阻塞
从衣食父母-浏览器中我们知道javascript脚本的执行是会阻塞DOM树的构建的,并且在cssom构建完毕前停止执行,这样会有很大的性能开销,有没有不阻塞的方法呢?
1、外部js异步加载
<script src="app.js" async></script>
2、 内联js异步执行
function h () { console.log(document.querySelectorAll('h1')) } setTimeout(h, 0)