美文网首页
前端——从输入URL到页面加载中间发生了什么

前端——从输入URL到页面加载中间发生了什么

作者: 你这个人真的是 | 来源:发表于2018-03-27 13:36 被阅读0次

    概述

        浏览器,呈现用户所选择的web资源,资源的格式通常是HTML,也可以是PDF、IMAGE及其他方式。这些资源需要从服务器请求,用户通过URI(Uniform Resource Identifier统一资源标识符)来制定所请求资源的位置,然后显示在浏览器窗口中。那么,当我们在浏览器的地址栏输入URI后,到完整地呈现数据这个期间都发生了什么呢?今天,我想通过这个梳理出一个前端的完整的知识体系。
        从耗时的角度,浏览器请求、加载、渲染也个页面,时间花在下面五件事情上:
    1、DNS查询;
    2、TCP连接;
    3、HTTP请求即响应;
    4、服务器响应;
    5、客户端渲染。

    一、DNS查询

        DNS(Domain Name System域名系统),用于TCP/ICP网络,用来将主机名和域名转化为IP地址的工作,大致流程:

    • 如果浏览器有缓存,直接使用浏览器缓存,否则使用本级缓存,再没有就使用host;
    • 如果本地没有,就向dns域名服务器查询到对应的IP
          由于dns的解析很耗时,当解析域名过多的时候,便会导致首屏加载变得过慢。

    二、TCP连接

        http是一个基于TCP/IP通信协议进行数据的传输。
        TCP(传输控制协议)——应用程序之间通信。当应用程序希望通过TCP与另一个应用程序通信时,它会发送一个通信请求。在双方“握手”之后,TCP将在两个应用程序之间建立通信,直到一方或双方关闭为止。UDP(用户数据包协议,应用程序之间的简单通信)和TCP很相似,但更简单,可靠性也更低。
        IP(用户数据包协议)——计算机之间的通信。通过IP,消息或者其他数据被分割为小的独立的包,通过因特网,将每个包路由至目的地。

    建立连接的三次握手
    客户端:hello,你是server么?
    服务端:hello,我是server,你是client么
    客户端:yes,我是client
    

        建立连接成功后,接下来就正式传输数据。

    断开连接的四次挥手
    主动方:我已经关闭了向你那边的主动通道了,只能被动接收了
    被动方:收到通道关闭的信息
    被动方:那我也告诉你,我这边向你的主动通道也关闭了
    主动方:最后收到数据,之后双方无法通信
    

        相信很多面试者会经常被问到http请求方式中get和post的区别。

    GET方法:

    • 查询字符串(名称/值对)是在 GET 请求的 URL 中发送的;
    • GET 请求可被缓存;
    • GET 请求保留在浏览器历史记录中;
    • GET 请求可被收藏为书签;
    • GET 请求不应在处理敏感数据时使用;
    • GET 请求有长度限制;
    • GET 请求只应当用于取回数据;

    POST方法

    • 查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的;
    • POST 请求不会被缓存;
    • POST 请求不会保留在浏览器历史记录中;
    • POST 不能被收藏为书签;
    • POST 请求对数据长度没有要求;
          其实以上说的都只是GET、POST在http层面上的区别,在TCP/IP层面也有区别,也是二者真正的区别,即GET会产生一个tcp数据包,post两个。具体就是:
    • GET请求时,浏览器会把headers和data一起发送,服务器响应200(返回数据);
    • POST请求时,浏览器会先发送headers,服务器响应100 continue,浏览器再发送data,服务器响应200(返回数据)。

    三、HTTP请求响应

        HTTP(HyperText Transfer Protocol超文本传输协议),是基于TCP的应用层协议,是互联网的基础协议。历经了HTTP/0.9,HTTp/1.0,HTTP/1.1,HTTP/2 几个版本。

    HTTP/0.9

        发布于1991年,它不涉及数据包(package)传输,主要规定了客户端和服务器之间的传输方式,默认使用80端口。该版本只有GET请求方式,服务器只能回应HTML格式的字符串。当服务器发送完毕后,就关闭TCP连接。

    HTTP/1.0

        发布于1996年5月,增加了许多内容。

    • 可以发送任何形式的内容,包括文字、图像、视频、二进制文件等等;
    • 除了GET请求方式,还引入了POST和HEAD命令;
    • 请求和回应的格式也变了。每次通信都必须包括头信息(HTTP header),回应包含了状态码、缓存、内容编码等。
          该版本的缺点是每个TCP连接只能发送一个请求,数据发送完毕,连接就关闭,若还要请求其他资源,就必须再新建一个连接。为解决这个问题,可在请求时,使用Connection: keep-alive
    HTTP/1.1

        发布于1997年1月,进一步完善了HTTP协议,直到现在还是最流行的版本。
        1.1版的最大变化,是引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用。不用声明Connection: keep-alive。当客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。此外,还新增了 新增PUT、DELETE、PATCH、OPTIONS方法。
        该版本的缺点是,虽然它允许复用TCP连接,但在同一个TCP连接里,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着,这称为["队头堵塞"](Head-of-line blocking)。为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。比如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等。

    HTTP/2

        发布于2015年,它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。它有以下的一些特性:

    • 多路复用。为了解决HTTP/1.1中对头堵塞的问题,在该版本复用TCP连接时,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。举个例子,在一个TCP连接里面,服务器同时收到了A请求和B请求,先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
    • 首部压缩。HTTP请求是无状态的,即服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
    • 二进制分帧。HTTP/2 是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
    • 服务器推送。HTTP/2 允许服务器未经请求,主动向客户端发送资源。常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
    • 请求优先级。如果流被赋予了优先级,它就会基于这个优先级来处理,由服务器决定需要多少资源来处理该请求。
    HTTPS

        它是安全版的http,相当于ssl+http。每次在请求前,先建立ssl,确保接下来的通信是加密的,无法轻易被截取分析。

    四、服务器响应

        服务器处理完客户端的请求后要做出响应,很多时候可以通过状态码来判断:


    status.png

    不同范围状态的意义:

    • 1xx——指示信息,表示请求已接收,继续处理
    • 2xx——成功,表示请求已被成功接收、理解、接受
    • 3xx——重定向,要完成请求必须进行更进一步的操作
    • 4xx——客户端错误,请求有语法错误或请求无法实现
    • 5xx——服务器端错误,服务器未能实现合法的请求
      常见状态码:
    • 200——表明该请求被成功地完成,所请求的资源发送回客户端
    • 301 ——请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
      -302 ——临时移动。
    • 304——自从上次请求后,请求的网页未修改过,请客户端使用本地缓存
    • 400——客户端请求有错(譬如可以是安全模块拦截)
    • 401——请求未经授权
    • 403——禁止访问(譬如可以是未登录时禁止)
    • 404——资源未找到
    • 500——服务器内部错误
    • 503——服务不可用。服务器目前无法使用
    • 504——网关超时。服务器作为网关或代理,但是没有及时从上游服务器收到请求
    • 505—— HTTP版本不受支持。服务器不支持请求中所用的 HTTP 协议版本

    五、客户端渲染

        当下流行的浏览器有Webkit内核 的Chrome、Safari,Geoko内核的Firefox,Trident内核的IE,不同浏览器的内核不同,各个浏览器的渲染引擎的渲染过程也略有不同。今天主要讲述以Webkit为内核的Chrome浏览器的渲染过程。


    11.png

        上图是webkit渲染的主流程。我们可以看到,它大致分为以下五个步骤:
    1、处理HTML标记,构建DOM树;
    2、处理CSS标记,构建CSSOM树;
    3、将DOM树和CSSOM树合并成渲染树;
    4、布局渲染树,计算各元素的尺寸、位置;
    5、绘制渲染树,绘制页面像素信息。

    构建DOM树

        DOM是文档对象模型的缩写,它是html文档的对象表示。假设有这样一个HTML页面:

    <html>
      <head>
        <meta  name="viewport"  content="width=device-width,initial-scale=1">    
        <link href="style.css"rel="stylesheet">    
        <title>Critical Path</title>  
      </head>
      <body> 
        <p>
          Hello 
          <span>web performance</span>
          students
        </p>
        <div>
          <imgsrc="awesome-photo.jpg">
        </div>
      </body>
    </html>
    

    最后的DOM树如下:


    22.png

    构建CSSOM树

    CSS规则树的生成也是类似。例如有份css文件内容如下:

    body {
     font-size: 16px
    }
    p {
     font-weight:bold 
    }
    span {
      color: red 
    }
    p span {
     display:none 
    }
    img {
      float: right 
    }
    

    最终的CSSOM树:


    33.png

        值得注意的是,现代浏览器总是并行加载资源的。默认情况下,CSS是阻塞加载的,但它并不会阻塞DOM树的解析,它阻塞的是DOM的渲染,直至CSSOM树构建完成。因而为了避免看到长时间的白屏,我们尽可能早地提前加载CSS文件。

    构建渲染树

        一般来说,渲染树和DOM树是相对应的,但有一些不可见的DOM元素不会插入到渲染树中,如head这种不可见的标签或者 display:none等,所以也不是严格上的一一对应。

    绘制渲染树

        当我们通过js动态修改了DOM和CSS,会导致重新布局(Layout)或渲染(Repaint)。
    注意:Layout和Repaint的概念是有区别的:

    Layout,也称为Reflow,即回流。一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树.

    Repaint,即重绘。意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就可以了.

    什么会引起回流?

    1.页面渲染初始化
    2.DOM结构改变,比如删除了某个节点
    3.render树变化,比如减少了padding
    4.窗口resize
    5.最复杂的一种:获取某些属性,引发回流。

    回流一定伴随着重绘,重绘却可以单独出现。看以下示例:

    var s = document.body.style;
    s.padding = "2px";  // 回流+重绘
    s.border =  "1px solid red";  // 再一次 回流+重绘
    s.color = "blue"; // 再一次重绘
    s.backgroundColor =  "#ccc"; // 再一次 重绘
    s.fontSize = "14px"; // 再一次 回流+重绘
    // 添加node,再一次 回流+重绘
    document.body.appendChild(document.createTextNode('abc!'));
    

        在此我顺便插一句display:nonevisibility:hidden的区别。虽然二者皆表示隐藏元素,但 visibility在渲染树上是存在的,它在页面上仍有空间,只是被隐藏了,设置该值后只因起页面重绘;而display:none,将发生回流、重绘。

    六、参考链接

    相关文章

      网友评论

          本文标题:前端——从输入URL到页面加载中间发生了什么

          本文链接:https://www.haomeiwen.com/subject/djvkcftx.html