当我们在浏览器地址栏中输入网址时,页面会很快展现出来,这其中到底发生了什么?
总的来说分为如下几个过程:
1.输入url
2.域名解析
3.服务器处理请求
4.浏览器解析渲染页面
1.输入url
什么是url?
URL(Uniform Resource Locator),统一资源定位符,用于定位互联网上的资源,实际上就是网站网址。url的格式一般为:
协议类型://<主机名>:<端口>/<路径>/文件名
其中协议类型可以是http(超文本传输协议)、https、ftp(文件传输协议)、telnet(远程登录协议)、file等等。而http是最常见的网络传输协议,https则是进行加密的网络传输。
例如,以http://www.jianshu.com/u/hello.jpg,其中,“http”表示与web服务器通讯采用http协议,简书web服务器域名为www.jianshu.com,u/hello.jpg表示所访问的文件存在于web服务器上的路径。
IP是什么?
IP是因特网中的每台连接到网络的计算机为实现相互通信而遵循的规则协议。每个处于互联网中的设备都有IP 地址,形如 192.168.0.1,而127.0.0.1代表本机的 IP。IP又分为局域网IP和公网IP。而局域网 IP 和公网 IP 是有差别的。每个网站就是靠IP来定位的。
为了便于记忆或辨识,人们使用域名来登录网站,每个域名背后有对应的IP地址。
比如对于http://www.jianshu.com的URL,浏览器实际上不知道www.jianshu.com到底是什么东西,需要查找www.jianshu.com网站所在服务器的IP地址,才能找到目标,这就是下文要说的域名解析即DNS解析。
2.DNS解析
DNS充当了一个翻译的角色,实现了网址到实际ip地址的转换,那么它是如何进行转换的,
过程如下,
当用户在浏览器中输入url后,你使用的电脑会发出一个DNS请求到本地DNS服务器。本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动,DNS请求到达本地DNS服务器之后会有以下几个步骤:
1.本地 DNS服务器将该请求转发到互联网上的根域(根域没有名字,在DNS系统中就用一个空字符串来表示。例如www.baidu.com.现在的DNS系统都不会要求域名以.来结束,即www.baidu.com就可以解析了,但是现在很多DNS解析服务商还是会要求在填写DNS记录的时候以.来结尾域名。
2.根域将所要查询域名中的顶级域(比如要查询www.baidu,com,该域名的顶级域就是com)的服务器IP地址返回到本地DNS。
3.本地DNS根据返回的IP地址,再向顶级域(就是com域)发送请求, com域服务器再将域名中的二级域(即www.baidu.com中的baidu.com)的IP地址返回给本地DNS。
4.本地DNS再向二级域发送请求进行查询。
5.之后不断重复这样的过程,直到本地DNS服务器得到最终的查询结果,并返回到主机。这时候主机才能通过域名访问该网站。
DNS优化
如果每次都经过这么多步骤,是否太耗时间?如何减少该过程的步骤呢?那就是DNS缓存。
DNS缓存
DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
3.服务器处理请求
当浏览器得到相应的ip地址之后,会向服务器发送http请求,我们的web-server收到请求之后,会响应请求http response,有可能响应的就是一个HTML文本,来让浏览器可以浏览。
4.浏览器解析渲染页面
浏览器在收到HTML,CSS,JS文件后,它是如何把页面呈现到屏幕上的?下图对应的就是WebKit渲染的过程。
浏览器是一个边解析边渲染的过程。首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。这个过程比较复杂,涉及到两个概念: reflow(回流)和repain(重绘)。DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。
JS的解析是由浏览器中的JS解析引擎完成的。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)。JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。
浏览器在解析过程中,如果遇到请求外部资源时,如图像,iconfont,JS等。浏览器将重复1-6过程下载该资源。请求过程是异步的,并不会影响HTML文档进行加载,但是当文档加载过程中遇到JS文件,HTML文档会挂起渲染过程,不仅要等到文档中JS文件加载完毕还要等待解析执行完毕,才会继续HTML的渲染过程。原因是因为JS有可能修改DOM结构,这就意味着JS执行完成前,后续所有资源的下载是没有必要的,这就是JS阻塞后续资源下载的根本原因。CSS文件的加载不影响JS文件的加载,但是却影响JS文件的执行。JS代码执行前浏览器必须保证CSS文件已经下载并加载完毕。