url解析:html
用户输入URL地址web
浏览器解析URL解析出主机名后端
浏览器将主机名转换成服务器ip地址(浏览器先查找本地DNS缓存列表 没有的话 再向浏览器默认的DNS服务器发送查询请求 同时缓存)浏览器
浏览器将端口号从URL中解析出来缓存
浏览器创建一条与目标Web服务器的TCP链接(三次握手)bash
浏览器向服务器发送一条HTTP请求报文服务器
服务器向浏览器返回一条HTTP响应报文app
关闭链接 浏览器解析文档框架
若是文档中有资源 重复6 7 8 动做 直至资源所有加载完毕dom
html解析:
渲染树,表明一个文档的视觉展现,浏览器经过它将文档内容绘制在浏览器窗口,展现给用户,它由按顺序展现在屏幕上的一系列矩形对象组成,这些矩形对象都带有字体,颜色和尺寸,位置等视觉样式属性。对于这些矩对象,FireFox称之为框架(frame),Webkit浏览器称之为渲染对象(render object, renderer),后文统称为渲染对象。
每个渲染对象都表明着其对应DOM节点的CSS盒子,该盒子包含了尺寸,位置等几何信息,同时它指向一个样式对象包含其余视觉样式信息。
每个渲染对象都对应着DOM节点,可是非视觉(隐藏,不占位)DOM元素不会插入渲染树,如<head>
元素或声明display: none;
的元素,渲染对象与DOM节点不是简单的一对一的关系,一个DOM能够对应一个渲染对象,但一个DOM元素也可能对应多个渲染对象,由于有不少元素不止包含一个CSS盒子,如当文本被折行时,会产生多个行盒,这些行会生成多个渲染对象;又如行内元素同时包含块元素和行内元素,则会建立一个匿名块级盒包含内部行内元素,此时一个DOM对应多个矩形对象(渲染对象)。
建立渲染树后,下一步就是布局(Layout),或者叫回流(reflow,relayout),这个过程就是经过渲染树中渲染对象的信息,计算出每个渲染对象的位置和尺寸,将其安置在浏览器窗口的正确位置,而有些时候咱们会在文档布局完成后对DOM进行修改,这时候可能须要从新进行布局,也可称其为回流,本质上仍是一个布局的过程,每个渲染对象都有一个布局或者回流方法,实现其布局或回流。
最后是绘制(paint)阶段或重绘(repaint)阶段,浏览器UI组件将遍历渲染树并调用渲染对象的绘制(paint)方法,将内容展示在屏幕上,也有可能在以后对DOM进行修改,须要从新绘制渲染对象,也就是重绘,绘制和重绘的关系能够参考布局和回流的关系。
当它发现了某个部分发生了变化影响了布局,渲染树须要从新计算。
改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引发浏览器的repaint,根据元素的新属性从新绘制,使元素呈现新的外观。重绘不会带来从新布局,并不必定伴随重排; Reflow要比Repaint更花费时间,也就更影响性能。因此在写代码的时候,要尽可能避免过多的Reflow。
或许是因为一般会在JavaScript脚本中改变文档DOM结构,因而浏览器以同步方式解析,加载和执行脚本,浏览器在解析文档时,当解析到<script>
标签时,会解析其中的脚本(对于外链的JavaScript文件,须要先加载该文件内容,再进行解析),而后当即执行,这整个过程都会阻塞文档解析,直到脚本执行完才会继续解析文档。就是说因为脚本是同步加载和执行的,它会阻塞文档解析,这也解释了为何如今一般建议将<script>
标签放在</body>
标签前面,而不是放在<head>
标签里。如今HTML5提供defer和async两个属性支持延迟和异步加载JavaScript文件
固然咱们能够经过设置defer
和async
属性来异步加载不过重要的脚本
这两个属性都告诉浏览器,他可能会在后台加载脚本时继续解析HTML,而后再在加载后执行脚本,这样脚本下载不会阻止DOM构建和页面呈现。用户能够在全部脚本完成加载以前看到页面
二者的区别就是他们将在那一刻执行脚本,在这以前咱们须要了解浏览器为其加载的每一个网页追踪细粒度时间戳
domLoading
: 浏览器即将开始解析第一批收到的HTML文档字节domInteractive
: 表示浏览器完成对全部HTML的解析而且DOM构建完成的时间点domContentLoaded
: 表示DOM准备就绪而且没有样式表阻止JavaScript执行的时间点domComplete
: 全部处理完成,而且网页上的全部资源都已经下载完毕loadEvent
: 做为每一个网页加载的最后一步,浏览器会触发onload
事件,以便触发额外的应用逻辑defer
的执行将在domInteractive
完成以后,domContentLoaded
以前开始,他保证脚本将按照他们在HTML中出现的顺序执行,而且不会阻塞解析器
async
脚本在完成下载以后和窗口load
事件以前的某一个时间点执行,这意味着异步脚本可能不按他们在HTML中出现的顺序执行,这意味着他们可能会阻止DOM构建
<script src="app1.js" defer></script>
<script src="app2.js" defer></script>
<script src="app3.js" defer></script>
复制代码
defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时 HTML 并未中止解析,这两个过程是并行的。整个 document 解析完毕且 defer-script 也加载完成以后(这两件事情的顺序无关),会执行全部由 defer-script 加载的 JavaScript 代码,而后触发 DOMContentLoaded 事件。
defer 不会改变 script 中代码的执行顺序,示例代码会按照 一、二、3 的顺序执行。因此,defer 与相比普通 script,有两点区别:载入 JavaScript 文件时不阻塞 HTML 的解析,执行阶段被放到 HTML 标签解析完成以后。
<script src="app.js" async></script>
<script src="ad.js" async></script>
<script src="statistics.js" async></script>
复制代码
async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,若是已经加载好,就会开始执行——不管此刻是 HTML 解析阶段仍是 DOMContentLoaded 触发以后。须要注意的是,这种方式加载的 JavaScript 依然会阻塞 load 事件。换句话说,async-script 可能在 DOMContentLoaded 触发以前或以后执行,但必定在 load 触发以前执行。
从上一段也能推出,多个 async-script 的执行顺序是不肯定的。值得注意的是,向 document 动态添加 script 标签时,async 属性默认是 true
<script>
且没有defer或async属性的 标签时,会触发页面渲染,于是若是前面CSS资源还没有加载完毕时,浏览器会等待它加载完毕在执行脚本。参考