关于输入URL之后,网页到底做了什么(输入url后的加载过程)
从输入URL到页面加载完成,这中间到底发生了什么
精简版请直接跳往文末
文中包括
- TCP的三次握手;
- 浏览器页面的渲染过程;
- javascript异步原理,事件循环(event loop)和任务队列(task queue)
- TCP的四次挥手;
- HTTPS和HTTP工作原理及通信;
首先需要了解计算机的网络体系结构
- 应用层(HTTP,SMTP.FTP,POP3)
- 运输层(TCP,UDP)
- 网络层(IP(路由器))
- 数据链路层(网桥(CSMA/CD,PPP))
- 物理层(集线器)
这里需要注意的是,HTTP和TCP/UDP是两个不同层上的协议。http(HyperText Transfer Protocol超文本传输协议,所有的WWW(World Wide Web万维网)文件都必须遵守这个标准)是应用层的协议,而TCP/UDP是传输层的协议,http是再TCP/UDP之上的协议,http协议使用了TCP/UDP,http更加高级一点,但是没有很好的灵活性,也就是http使用起来比TCP/UDP要简单,只需要遵循规范就可以进行网络通信了。
接下来回到正题
1:查找域名对应的IP地址
IP地址:IP协议为互联网上的每一个网络和每一台主机分配一个逻辑地址。也就是说,IP实际上就是一个标签,为每一台电脑打上一个独有的标记。而服务器本质也是一台主机,想要访问某个服务器,就要先知道它的IP。
IP和域名并不是一一对应的关系,可以把多个提供相同的服务器的IP设置为同一个域名,但是在同一时刻一个域名只能解析出一个IP地址;同时,一个IP地址可以绑定多个域名,数量不限
域名:IP地址是由四组数字组成的,再使用过程中比较难记忆,因此使用了字母来代替数字,域名通过DNS解析到固定IP上,这样就可以通过域名来访问到固定IP。(例如www.baidu.com)
域名和URL是两个完全不同的东西:域名是一台或一组服务器的名称,用来确定服务器在Internet上的位置,而URL是统一资源定位符,用来确定某一个文件的具体位置(www.baidu.com这是域名,http://www.jianshu.com/p/3944732228f0这个是URL)
DNS:每个域名都对应一个或多个提供相同服务服务器的IP地址,叫做DNS解析(例如:A解析和Cname解析)
查找域名对应的IP地址,具体要分为以下几步
- 浏览器搜索自己的DNS缓存。
- 搜索操作系统中的DNS缓存。
- 搜索操作系统的hosts文件(windows系统下,维护一张域名与IP地址的对应表(类似于遵循域名与IP对应的关系))
- 操作系统将域名发送至LDOS(本地区域名服务器,如果是学校,这个LDNS服务器就在学校,如果是电信,LDNS服务器就在当地电信),查找成功则返回结果,失败则发起一个迭代DNS请求。(这时LDNS将向ROOt Name Sever及根域名服务器发起请求,此处将返回你搜索的域的顶级域名服务器地址(比方说你搜索的是baidu.com,它将会返回com域的顶级域名服务器地址,这之后还有两步...详情需要百度))
- LDNS将得到的IP地址返回给浏览器,同时自己也将IP缓存起来。
- 操作系统量IP地址返回给浏览器,同时自己也将IP缓存起来。
- 于是浏览器就得到了域名对应的IP地址,(然而这仅仅是开始)
2:浏览器根据IP地址与服务器建立socket链接(TCP的三次握手)
当我们得到了服务器的IP地址之后,就可以开始连接了,这里的通讯链接需要经历以下三个过程,因此被叫做TCP的三次握手:
- 客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认(主机向服务器发送一个建立链接的请求);
- 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个syn包(syn=k),既syn+ack包,此时服务器进入syn_recv状态(服务器接到请求后发送同意连接的信号)
- 客户端收到服务器的syn+ack包,向服务器发送确认包ack(ack=k+1),此包发送完毕,客户端和服务器进入established状态,完成三次握手(主机接到同意信息后,再次向服务器发送了确认信号)
这里的三次握手,采用了TCP协议,其可以保证信息传输的可靠性,三次握手过程中,万一有一方收不到确认信号,协议会要求重新发送信号。
3:浏览器与服务器通信:浏览器请求,服务器处理请求
当服务器与主机建立了链接后,主机就与服务器进行通信。网页请求是一个单项请求的过程,那就是一个主机向服务器请求数据,服务器返回相应的数据的过程。
- 浏览器根据URL(这里是URL)内容生成HTTP请求,请求中包含请求文件的位置,请求文件的方式等。
- 服务器接到请求后,会根据HTTP请求中的内容来决定如何获取相应的HTML文件。
- 服务器将得到的HTML文件发送给浏览器。
- 在浏览器还没有完全接收HTML文件时便开始渲染,显示网页。
- 在执行HTML中代码时,根据需要,浏览器会继续请求图片,css,js等文件。
浏览器渲染展示网页的过程
- HTML代码转化为DOM(DOM Tree)
- CSS代码转化成CSSOM(CSS Object Model)
- 结合DOM和CSSOM,生成一棵渲染树(包含每个节点的视觉信息)(Render Tree)
- 生成布局(layout),将所有渲染树的所有节点进行平面合成
- 将布局绘制(paint)在屏幕上
- 使用JavaScript脚本来动态的修改DOM,以便给Web应用带来动态行为
- Web应用的执行分为两个阶段
- 全局JavaScript代码遇到script节点时执行。在这个执行过程中,其能够以任意程度改变当前的DOM(有可能触发页面的重绘和回流)
- 关于事件处理,在同一时刻,只能处理多个不同事件中的一个,处理顺序是事件的生成循序(队列顺序),事件处理阶段大量依赖事件队列,事件循环会检查事件队列的头部,如果检测到了一个事件,相应的事件处理器就会被调用(详情见文末)
4:浏览器与服务器断开连接(四次挥手)
- 主机向服务器发送一个断开连接的请求。
- 服务器接到请求后发送确认收到请求的信号。
- 服务器向主机发送断开通知。
- 主机接到断开通知后断开连接并反馈一个确认信号,服务器收到确认信号后断开连接
为什么服务器在接到断开请求时不立即同意断开:当服务器收到断开连接的请求时,可能仍然有数据未发送完成,所有服务器先发送确认信号,等所有数据发送完毕后在同意断开
四次挥手之后,主机发送确认信号后并没有立即断开连接,而是等待2个报文传送周期,原因是:如果四次挥手的确认信息丢失,服务器将会重新发送第三次挥手的断开连接的信号,而服务器发觉丢包与重新发送的断开连接到达主机的时间正好为2个报文传输周期
注释
- HTTPS与HTTP的区别
HTTPS:HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息;
浏览器与网站互相发送加密的握手消息并验证,是为了保证双方都有一致的密码,为后续真正的数据传输做一次测试
HTTPS的工作原理
- 浏览器将自己支持的一套加密规则发送给网站;
- 网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
- 浏览器获得网站证书之后验证证书的合法性(如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密)
- 使用约定好的HASH算法计算握手消息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给网站
HTTPS和HTTP协议的区别
- https协议需要到ca申请证书,一般免费证书很少,需要交费。
- http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的 。无状态的意思就是给他一样的参数你要有一样的结果,通过增加cookie和session机制,现在的网络请求其实是有状态的。
- HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议, 要比http协议安全。
- 事件循环(event loop)和事件队列(task queue)
JS的异步机制由事件循环和任务队列构成。JS本身是单线程语言,所谓异步依赖于浏览器或者操作系统等完成。JavaScript主线程拥有一个执行栈以及一个任务队列,主线程会依次执行代码,当遇到函数时,会先将函数入栈,函数运行完毕后再将该函数出栈,直到所有代码执行完毕。
遇到异步操作(例如:setTimeout, AJAX)时,异步操作会由浏览器(OS)执行,浏览器会在这些任务完成后,将事先定义的回调函数推入主线程的任务队列(task queue)中,当主线程的执行栈清空之后会读取task queue中的回调函数,当task queue被读取完毕之后,主线程接着执行,从而进入一个无限的循环,这就是事件循环.
Microtask 与 Macrotask
一个浏览器环境只能拥有一个事件循环(event loop),而一个事件循环可以多个任务队列(Task queue),每个任务都有一个任务源(Task source)。任务队列是一个先进先出的队列.macrotask(macro-task: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering) 和 microtask(micro-task: process.nextTick, Promises(这里指浏览器实现的原生 Promise), Object.observe, MutationObserver) 是异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
全部代码(script)是一个macrotask,js先执行一个macrotask,执行过程中遇到(setTimeout, setInterval, setImmediate等)异步操作则创建一个macrotask,遇到(process.nextTick, Promises等)创建一个microtask,这两个queue分别被挂起.执行栈为空时开始处理macrotask,完成后处理microtask,直到该microtask全部执行完,然后继续主线程调用栈.
每一次事件循环(one cycle of the event loop),只处理一个 (macro)task。待该 macrotask 完成后,所有的 microtask 会在同一次循环中处理。处理这些 microtask 时,还可以将更多的 microtask 入队,它们会一一执行,直到整个 microtask 队列处理完。
<script type="text/javascript"> console.log(1) setTimeout(function(){ console.log(2); let promise = new Promise(function(resolve, reject) { console.log(6); resolve() }).then(function(){ console.log(7) }); },0); let promise = new Promise(function(resolve, reject) { console.log(3); resolve() }).then(function(){ console.log(4) }).then(function(){ console.log(8) }); console.log(5) </script>
以上代码的打印顺序 1>3>5>4>8>2>6>7
- 页面的重绘和回流
在生成render tree之后,浏览器绘制页面(paint),此时会触发回流与重绘
回流
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。
以下是会触发回流的几种情况
- 添加或者删除可见的DOM元素;
- 元素位置改变;
- 元素尺寸改变——边距、填充、边框、宽度和高度
- 页面渲染初始化;
- 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
- 浏览器窗口尺寸改变——resize事件发生时;
重绘
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
回流必将引起重绘,而重绘不一定会引起回流。
举个栗子
当我们在浏览器中输入www.baidu.com时,直到我们呈现出页面,会发生以下事情(Chrome浏览器)
- 首先 Chrome 搜索自身的 DNS 缓存。(如果 DNS 缓存中找到百度的 IP 地址,就跳过了接下来查找 IP 地址步骤,直接访问该 IP 地址。)
- 搜索操作系统自身的 DNS 缓存。(浏览器没有找到缓存或者缓存已经失效)
读取硬盘中的 host 文件,里面记录着域名到 IP 地址的映射关系,Mac 电脑中位于 /etc/hosts。(如果前1.2步骤都没有找到) - 浏览器向宽带运营商服务器或者域名服务器发起一个 DNS 解析请求,这里服务器有两种方式解析请求,这在稍后会讲到,之后浏览器获得了百度首页的 IP 地址。
- 拿到 IP 地址后,浏览器就向该 IP 所在的服务器建立 TCP 连接(即三次握手)。
- 连接建立起来之后,浏览器就可以向服务器发起 HTTP 请求了。(这里比如访问百度首页,就向服务器发起 HTTP 中的 GET 请求)
- 服务器接受到这个请求后,根据路径参数,经过后台一些处理之后,把处理后的结果返回给浏览器,如果是百度首页,就可以把完整的 HTML 页面代码返回给浏览器。
- 浏览器拿到了百度首页的完整 HTML 页面代码,内核和 JS 引擎就会解析和渲染这个页面,里面的 JS,CSS,图片等静态资源也通过一个个 HTTP 请求进行加载。
- 浏览器根据拿到的资源对页面进行渲染,最终把完整的页面呈现给用户。如果浏览器没有后续的请求,那么就会跟服务器端发起 TCP 断开(即四次挥手)。