学习笔记-浏览器如何工作
一、前端基础:
1、前端三要素:HTML、CSS、JS,通过三种技术的融合产生了各式各样的网站。
- HTML(内容):各种内容标签组成,文字、图片、动画、声音、表格、超链接等网页元素都是由HTML提供。
- CSS(表示):控制和调整网页的样式,与网页的结构和内容没有关系。
- JS(行为):完成复杂的程序逻辑,主要负责网页的各式各样的动态功能。
2、HTML(HyperText Markup Language)
HTML是超文本标记语言,主要用来实现静态页面,包括网站页面的主要内容和主体框架。HTML是由各种标签组成的,所学习HTML就是在了解HTML主体框架的结构基础上学习各种标签的使用方法。
HTML主要由 <html>、<head>、<body>三个基本元素组成,一个标准的HTML结构如下:
- HTML文档声明:告诉浏览器该文件是HTML类型的文本文件,浏览器会按照html的规则去解析该文件。
- head元素:包含该文件的一些头信息,文档的头部描述了文档的各种属性和信息,包括文档的标题、在 Web 中的位置以及和其他文档的关系等。
- body元素:定义文档的主体,body 元素包含文档的所有内容,比如文本、超链接、图像、表格和列表等。
index.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>HTML基础</title> 6 </head> 7 <body> 8 <h1>标题标签</h1> 9 <p>段落标签</p> 10 <a href="https://www.runoob.com/html/html-basic.html" target="_blank" rel="noopener noreferrer">其他标签学习</a> 11 </body> 12 </html>
3、CSS(Cascading Style Sheets)
CSS是层叠样式表,主要用来控制如何显示HTML元素,比如 文本颜色、文本大小、表格边框等。
CSS编写方式:内联样式、内部样式、外部样式
- 内联样式:直接在标签的 style 属性中书写
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>CSS 内联样式</title> 6 </head> 7 <body> 8 <h1>不带样式(默认样式)</h1> 9 <h1 style="text-align:left; color:rgba(33, 160, 139, 0.9); font-weight:bold; font-family:STKaiti; font-size:150px">带样式</h1> 10 </body> 11 </html>
- 内部样式:在html的 style 标签中书写
1 <html> 2 <head> 3 <meta charset="utf-8"> 4 <title>CSS 内部样式</title> 5 <style type="text/css"> 6 body h2{color:rgba(33, 160, 139, 0.9); font-weight:bold; font-family:STKaiti; font-size:150px} 7 </style> 8 </head> 9 <body> 10 <h1>不带样式</h1> 11 <h2>带样式</h1> 12 </body> 13 </html>
- 外部样式:将所有的样式放在一个或多个以CSS文件中,再通过Link的方式将CSS所写的样式添加到HTML中
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>CSS 外部样式</title> 6 <link rel="stylesheet" type="text/css" href="mystyle.css"/> 7 </head> 8 <body> 9 <h1>不带样式</h1> 10 <h2 >带样式</h1> 11 </body> 12 </html>
1 body h2 { 2 text-align:left; 3 color:rgba(33, 160, 139, 0.9); 4 font-weight:bold; 5 font-family:STKaiti; 6 font-size:150px; 7 }
CSS选择器
选择器用于选取需设置样式的元素,大致分为:
- 元素选择器 p
- id选择器 #id
- 类选择器 .class
- 属性选择器 p[id]
- 后代选择器 div p
- 子元素选择器 div>p
- 相邻兄弟选择器 div+p
- 组合选择器
4、JS(JavaScript)
JS一种完整的网页脚本语言,有自己独立的语法,可以完成复杂的程序逻辑,而HTML和CSS仅仅是标记语言,不具备编程语言的程序逻辑。
JS主要负责网页的各式各样的动态功能,比如 用户输入验证,改变HTML内容、改变HTML样式等。
JS的工作原理是通过在HTML网页中直接嵌入JS脚本,可以实现相应浏览器时间,读写HTML元素内容,更改HTML元素样式等功能
JS简单用法:
HTML 中的JS脚本必须位于 <script> 与 </script> 标签之间。包含JS脚本的<script>可被放置在 HTML 页面的 <body> 和 <head> 部分中
- 内部引入
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>JS基本用法</title> 6 <script> 7 function myFunction(){ 8 document.getElementById("demo").innerHTML="我的第一个 JavaScript 函数"; 9 } 10 </script> 11 </head> 12 <body> 13 <h1>我的 Web 页面</h1> 14 <p id="demo">一个段落。</p> 15 <button type="button" onclick="myFunction()">点击这里</button> 16 </body> 17 </html>
- 外部导入
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>JS基本用法</title> 6 <script src="js/myFunction.js"></script> 7 </head> 8 <body> 9 <h1>我的 Web 页面</h1> 10 <p id="demo">一个段落。</p> 11 <button type="button" onclick="myFunction()">点击这里</button> 12 </body> 13 </html>
JS输入验证:
用户输入通过JS脚本进行验证,达到网页与用户动态交互的目的
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 </head> 6 <body> 7 <h1>JavaScript 验证输入</h1> 8 <p>请输入 1 到 10 之间的数字:</p> 9 <input id="numb"> 10 <button type="button" onclick="myFunction()">提交</button> 11 <p id="demo"></p> 12 <script> 13 function myFunction() { 14 var x, text; 15 // 获取 id="numb" 的值 16 x = document.getElementById("numb").value; 17 // 如果输入的值 x 不是数字或者小于 1 或者大于 10,则提示错误 Not a Number or less than one or greater than 10 18 if (isNaN(x) || x < 1 || x > 10) { 19 text = "输入错误"; 20 } else { 21 text = "输入正确"; 22 } 23 document.getElementById("demo").innerHTML = text; 24 } 25 </script> 26 </body> 27 </html>
JS元素查找:
通过 JavaScript,您需要操作 HTML 元素,为了做到这件事情,必须首先找到该元素。
- 通过ID获取(getElementById):返回值为取到第一个id属性相符的元素
- 通过name属性(getElementsByName):通过元素name属性查找元素,返回值是元素数组,没有找到返回空数组
- 通过标签名(getElementsByTagName):通过元素名查找元素,返回值是一个元素数组,元素的顺序是它们在文档中的顺序,没有找到返回空数组
- 通过类名(getElementsByClassName):通过元素class属性查找元素,返回值是元素数组,没有找到返回空数组
- 通过选择器获取一个元素(querySelector):返回匹配指定选择器的第一个元素
- 通过选择器获取一组元素(querySelectorAll):匹配指定 CSS 选择器的所有元素,返回值是元素数组
- 获取html的方法(document.documentElement):获取DOM树根节点元素,document.documentElement是专门获取html这个标签的
- 获取body的方法(document.body):document.body是专门获取body这个标签的
5、小结:
HTML-内容 CSS-样式 JS-行为
二、浏览器如何运作
1、浏览器
浏览器是向服务器发出请求,并为用户在窗口中展示网络资源(HTML文档,图片、PDF等)的软件。
浏览器主要组件:用户界面、浏览器引擎、渲染引擎
2、进程与线程
进程:是操作系统资源分配和资源调度的最小单元,可以申请和拥有计算机资源,进程是程序的基本执行实体
线程:是操作系统进行运算调度的最小单位,一个进程可以并发多个线程,每个线程并行执行不同的任务
3、chrome浏览器
chrome浏览器是多进程应用程序:浏览器进程、GPU进程、缓存进程、网络进程、插件进程、渲染器进程
chrome是多进程构架:
chrome由浏览器进程、渲染进程、插件进程、GPU进程等组成,chrome每个tab页可能对应多个渲染器进程,这和启动chrome时选择的进程模型有关。chromium官方文档:chrome支持四种进程模型Process-per-site-instance(默认)、Process-per-site、Process-per-tab、Single process
- Process-per-site-instance:每个tab页中的站点对应不同渲染器进程
- Process-per-site:每个tab页对应一个渲染器进程,tab页同一站点对应同一个进程
- Process-per-tab:一个tab页里的所有站点使用一个进程
- Single process:浏览器引擎和渲染引擎共用一个进程
各进程作用:
- 浏览器进程:控制用户界面,包括地址栏、书签、回退、前进按钮,以及处理web浏览器不可见的特权部分,如网络请求、文件访问等
- 渲染进程:控制tab页内网站展示
- 插件进程:控制站点使用的任意插件,如flash
- GPU进程:处理独立于其他进程的GPU任务。GPU被分成不同进程,因为GPU处理来着多个不同应用的请求并绘制在相同表面
chorme多进程构架的优点:
- 规避单个tab页未响应,所有tab页都挂死的风险
- 安全性和沙箱化,限制和保护某些特定功能的进程,如限制处理任意用户输入的进程(渲染器进程)对任意文件的访问
- 提升运行效率
工作流程:
步骤1.浏览器进程的UI线程捕捉地址栏输入内容,如果是网址,UI线程会启动一个网络线程来请求DNS进行域名解析,开始连接服务器获取数据。如果是关键词,浏览器会使用默认配置的搜索引擎来查询。
步骤2. 获取到数据后,会通过SafeBrowsing(google内部站点安全系统)来检查是否是恶意站点
步骤3. 数据安全校验通过后,UI线程会创建一个渲染器进程来渲染页面,浏览器进程通过IPC将数据(html)传递给渲染器进程,开始渲染流程(将html,css,js,img等资源渲染成用户可以交互的web页面)
步骤4. 渲染器进程的主线程将HTML进行解析,构造DOM数据结构。HTML首先经过Tokeniser标记话,通过词法分析将输入的HTML内容解析成多个标记,根据识别后的标记进行DOM树构造(涉及重绘和重排的问题),首先会创建document对象,以此为根节点不断修改和构造,想DOM树中添加各元素节点。
HTML代码中会涉及图片、CSS、JS等,图片和CSS不会阻塞HTML的解析,解析过程中遇到<Scritp>标签,则会停止HTML解析,转而加载和执行JS代码。所以JS代码要放在合适的位置或者用async/defer属性来异步执行JS
注释:
DOM(Document Object Model):
文档对象模型,是浏览器对页面在其内部的表示形式,是程序员通过JS与之交互的数据结构和API,通过它开发者可以添加,删除和修改页面的各个部分。
任何HTML文档都可以用DOM表示一个由节点构成的层级结构,层级关系也可以表示为一个特定节点为根的树形结构。
步骤5. 获取到DOM树后,渲染器进程主线程需要解析CSS,确定每个DOM节点的样式(style)
步骤6. 确定DOM节点样式后,渲染器进程主线程需要确认节点的位置布局(layout),主线程通过遍历DOM和计算好的样式来生成Layout Tree,Layout Tree每个节点都记录了x,y坐标值,边框尺寸等。
注意:DOM Tree和Layout Tree并不是一一对应的,Layout Tree只和最后展示在屏幕上的节点是对应的
步骤7. 知道样式和位置后,渲染器进程主线程还需要确定按什么顺序绘制(paint)节点,比如不可以简单按照DOM树结构绘制,z-index可以改变绘制的层级关系。主线程会遍历Layout Tree创建一个绘制记录表(Paint Record),该表记录了绘制的顺序。
步骤8. 栅格化(Rastering),涉及到合成(Compositing)的栅格化方案。渲染器进程主线程遍历Layout Tree生成Layer Tree(图层树),主线程将这些信息传递给合成器线程,合成器线程将这些图层栅格化(合成器线程将每一层分割成很多图块(tiles),并将图块发送给栅格线程(Raster Thread),栅格线程将栅格化每个图块并存储在GPU内存中。合成器线程将收集”draw quads“的图块信息(记录了图块在内存中的位置以及页面绘制位置,合成器线程合成一个合成器帧(Compositor Frame))
步骤9. 渲染器进程主线程将合成器帧通过IPC传送给浏览器进程,接着浏览器进程将合成器帧传送到GPU,GPU渲染展示到屏幕上,依此往复每一帧。
4、小结
HTML——>DOM——>样式(style)——>布局(layout)——>绘制(paint)——>图层化(layer)——>栅格化(Rastering)——>合成器帧(Compositor Frame)——>GPU渲染展示到屏幕
拓展:重排和重绘
重排:当改变元素的尺寸和位置属性时,会重新进行样式计算(Computed Style)、布局(Layout)、绘制(Paint)以及后面的所有流程。
重绘:当改变元素的颜色属性时,不会触发布局(Layout),但是还是会样式计算(Computed Style)和绘制(Paint)以及后面的所有流程。
因为重排、重绘都会占用渲染器进程主线程,如果程序员写了一个不断重排/重绘的页面,浏览器在每一帧都会进行样式计算、布局、绘制的操作,如果同时还有大量JS操作,页面就容易出现卡顿(每秒60帧呈现才不会出现卡顿).
参考资料:
https://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
https://juejin.cn/post/6844903679389073415
https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/
https://www.bilibili.com/video/BV1x54y1B7RE/?spm_id_from=333.788.recommend_more_video.-1
https://www.runoob.com/html/html-tutorial.html
https://www.boxuegu.com/news/3953.html