必备-2.浏览器底层渲染机制全套详解

必备-2.浏览器底层渲染机制全套详解

一、如何创建一个个人的网站

我们如何发布一个自己的网站,可以供别人看?

  • 第一步:购买一台服务器:阿里云、腾讯云

    • 每台服务器都有一个自己的外网IP:123.111.222.12
  • 第二步:基于FTP上传工具[fileZilla]将自己创作的网站代码,放到服务器的磁盘空间中(服务器本质就是一台电脑)

  • 第三步:基于nainx、apache、iis等把作品进行发布:在服务器创建一个web服务,让其管理项目资源(一台服务器可以有多个服务

    • 到目前为止:别人基于IP地址+端口号 就可以访问到我们的内容了,(但是这样访问太麻烦了
  • 第四步:这时就需要购买域名:域名的作用就是简化服务器web服务的访问方式

    • 无域名访问:ip地址+端口号

    • 有域名访问:www.baidu.com

    • 购买到域名后,通过DNS解析,使域名与服务器外网IP连接起来,把解析记录放到DNS服务器中。

    • 最后,到工信部备案

如何以开一家超市的例子来理解发布一个网站的全过程?

  • 举例:我们如果想开一家超市需要有几个前提条件:

  • 超市地址->货物->货物类型分区(蔬菜、家电、玩具…)->各专区服务员->取一个超市名->将超市名做成招牌,安到超市门口->到工信部注册,办营业许可证

    • 这其中超市的创建步骤,其实与服务器创建的步骤可以一一对应的:
      • 超市地址:服务器外网IP
      • 货物:自己写的项目
      • 货物类型分区:多个项目,每一个项目都是一个分区
      • 各专区服务员:端口号
      • 超市名:域名->www.baidu.com
      • 超市名做成招牌,安门口:DNS解析,外网IP连接域名
      • 营业许可证:到工信部注册

二、URL请求网址过程

从输入URL地址到看到页面中间都经历了啥?

一共分七步

  • 第一步:URL地址解析
  • 第二步:缓存检查
  • 第三步:DNS解析
  • 第四步:TCP三次握手(目的:建立客户端与服务器端的通道)(修路)
  • 第五步:基于HTTP或HTTPS等实现通信
  • 第六步:TCP四次挥手
  • 第七步:浏览器渲染获取的代码

1.URL地址解析

URL地址:http://www.xxx.com:80/index.html?name=sjh&age=18#video;

  • 1、http:传输协议:[作用:用户客户端和服务器端的信息传输]
    • http:超文本传输协议[最常用]
    • https:http+SSL[比http更安全的传输机制]
    • ftp:文件传输协议,把本地开发的资源上传到服务器
  • 2、www.xxx.com域名:[作用:给外网IP起一个好听的名字]
    • 顶级域名:xxx.com[需要购买]
    • 一级域名:www.qq.com
    • 二级域名:sports.qq.com
    • 三级域名:kbs.sports.qq.com
  • 3、80端口号:[作用:区分相同服务器上的不同服务的 0~65535]
    • 浏览器有一个默认操作,如果我们自己没有写端口号,浏览器会根据传输协议自己加上默认的端口号
      • http->80
      • https->443:https://www.baidu.com->https://www.baidu.com:443/
      • ftp->21
  • 4、index.html:请求资源的路径名称[如果不写,则一般默认都是index.html(服务器可以自己指定默认路径]
  • 5、问号传参
    • 把信息传递给服务器
    • 在页面跳转的过程中,基于问号参数传递给另外一个页面一些信息
  • 6、#video哈希值
    • 锚点跳转
    • HASH路由

2.缓存检查

  • 缓存方式有三种强缓存、协商缓存、数据缓存
  • 缓存位置有两种
    • 内存条:[Memory Cache]虚拟内存缓存(临时)
    • 硬盘:[Disk Cache]物理内存缓存(持久)
  • 缓存存取方式三种:最开始从服务器获取信息,如果存在缓存机制,则会在MemoryDisk各存储一份
    • 普通刷新(F5):从Memory Cache 中获取
    • 页面关闭再重新打开:从Disk Cache中获取
    • 强制刷新(Ctrl+F5):清除本地缓存,重新从服务器获取最新的内容
2.1强缓存

强缓存:本地存在缓存(且未过期),则直接从本地缓存中获取渲染{不论服务器端是否更新了内容},如果没有缓存(或者过期了),才从服务器重新获取;

  • 实现步骤

    • 第一次向服务器发送请求(本地无缓存):服务器把信息返回给客户端[同时在响应头中设置Expires或者Cache-Control]:用来规定是否设置强缓存以及缓存的周期;客户端获取信息后,渲染的同时,根据缓存的规则,把信息缓存在本地;
      • Cache-Control:max-age=2592000 单位秒 Http1.1
      • expries: 具体时间 Http1.0
      • 两个都被服务器返回,则按照浏览器HTTP版本的支持度,去最高版本支持的项,http1.1比http1.0高
    • 第二次向服务器发送请求(本地有缓存):先看本地是否有缓存以及是否过期,有且未过期,直接读取缓存的信息,如果缓存失效,则从服务器重新获取…,重新获取后再把最新的内容缓存到本地
  • 如何设置强缓存:是由服务器端在响应头中基于Expires和Cache-Control设置缓存规则的,二客户端自己会根据这些规则,完成强缓存的存储及校验。

  • 强缓存的作用:保证第二次及以后访问资源更快,对第一次没啥特殊效果!

  • 强缓存的副作用:在缓存有效期内,服务器资源更新了,我们获取的也是本地缓存信息,无法获取最新的信息。所以真实项目中,HTML页面是"绝对不能设置强缓存的",一旦html都缓存了,则和服务器彻底失联了,服务器不论如何更新,客户在缓存有效期内都无法获取最新的资源。

    • 加载一个页面,首先获取的是html,在浏览器渲染html的时候,遇到link/script/img等标签,才会从服务器获取这些资源信息。
    • 解决方法html文件不做缓存,服务器端只要代码更改,我们让其在html中重新导入新的文件名[使用webpack实现],我们下次再访问html页面时,新导入的文件会重新向服务器请求
  • 强缓存特点:不论是从服务器获取的还是从缓存中读取的资源,返回状态码都是200。

2.2协商缓存
  • 协商缓存:如果强缓存和协商缓存都设置了,必须等待强缓存失效后,才会执行协商缓存(协商缓存是对强缓存的一种辅助)
    • 实现步骤
      • 第一次向服务器发送请求:服务器返回对应的资源信息[同时在响应头中返回两个字段]:
        • last-modified(HTTP 1.0):当前资源最后一次更新时间
        • etag(HTTP1.1):只要服务器资源更新就会产生一个唯一的etag值
        • 当客户端获取信息之后,发现存在这两个字段会在客户端本地存储资源信息及相关表示字段
      • 第二次发送请求:即便发现本地有缓存信息,也需要先和服务器协商【协商内容:问一下服务器,这个资源有没有再更新过?】
        • 客户端把自之前缓存中的last-modifiedetag基于请求头中的If-Modified-SinceIf-Node-Match发送给服务器,服务器根据传递过来的文件更新时间(标识)和目前服务器最新的更新时间(标识)去对比
        • 两次时间(标识)一致:说明服务器资源距离上一次缓存没有任何的更新,此时服务器返回304状态码即可,客户端接收到这个状态后,从本地缓的信息中获取渲染即可
        • 如果不一致:说明更新过,返回状态码200以及最新的信息(和新的last-modified和etag),客户端再重新渲染并缓存最新的信息
    • 协商缓存也是由服务器设置的:在响应头中返回last-modifiedetag
    • 协商缓存是对于强缓存的一种补充:对于html页面无法设置缓存但是可以设置协商缓存、而且在强缓存失效的情况下,我们依然可以基于协商缓存验证一下服务器是否更新

-------------------------》不论强缓存还是协商缓存,都是服务器设置的[在响应头返回对应的字段],而客户端需要做的事情,浏览器自己就处理了,不需要我们前端写啥代码:而且都是针对于静态资源文件的缓存设置(例如:html、css/js/图片…),对于ajax数据请求,强缓存和协商缓存是无效的。

2.3数据缓存
  • 数据缓存:[ajax数据通信的时候,对于不经常更新的数据,我们基于本地存储实现缓存]
    • 实现步骤
      • 第一次本地没有存储过任何信息:此时向服务发送ajax请求,从服务器获取数据,获取数据后一方面进行数据绑定和渲染,另外一方面把数据存储到本地【基于本地存储方案、设置有效时间】
      • 后期再发送请求:首先看本地是否存储过这些数据,且是否过期
        • 存储过且未过期:不需要从服务器获取,只需要获取本地存储的内容即可
        • 未存储或者过期了:重新向服务器发送请求获取最新的信息,同时本地也把最新内容存储
    • 数据缓存需要前端开发工程师基于 JS代码+本地存储方法,自己去实现
    • 本地存储方案:把一些信息存储到本地(Application->Storage)应用->数据库
      • 特点:明文存储而且可以被查看(所以重要敏感信息不要存储,即便存储也要加密)
        • 而且存储的信息都是以字符串类型进行存储[排除虚拟内存存储]
        • 有源的限制(在某个域下存储的信息,只能在本域中获取)

数据缓存存储的方案有哪些?

  • @1 cookie:一段小文本信息(key-value格式)
  • @2 localStore:本地数据库
  • @3 sessionStore:会话数据库
  • @4 vuex/redux:
  • @5 IndexedDB:@5和@6都是本地数据库存储,很不常用
  • @6 WebSQL:

数据缓存存储中,cookie、localStorage、sessionStorage、vuex/redux的区别?

  • 兼容性
  • cookie:兼容所有浏览器
  • localStorage/sessionStorage:H5新增的API,不兼容IE6~8
  • 存储内容大小:
    • cookie:同源下最多允许4kb
    • localStorage/sessionStorage:同源下最多允许存储5MB
  • 有效期:
    • cookie:持久化存储,具备存储有效期,需要自己设置
    • localStorage:持久化存储,除非手动删除,否则一直存着,不具备有效期
    • sessionStorage:临时存储,页面刷新还在,关闭页面就没了
    • vuex/redux:临时存储,页面刷新就没了
  • 稳定性
    • cookie:不稳定,清除历史记录、电脑垃圾会清除cookie,网站无痕模式下禁止存放cookie
    • localStorage/sessionStorage:稳定,干掉cookie的那些操作暂时都干不掉localeStorage/sessioStore
  • 与服务器关系
    • cookie:无论服务器需不需要,每次请求,都会在请求头中携带cookie,影响请求速度
    • localStorage/sessionStorage:绝对的本地存储,和服务器之间没有任何关系,可手动向服务器传缓存

数据缓存各存储方式详解?

  • @1 cookie:
    • document.cookie:获取所有Cookie
    • document.cookie=(name,value):设置Cookie
    • 优点:兼容所有的浏览器,是传统的本地存储方案
    • 缺点:存储内容大小有限制,同源下最多允许4kb
    • 有效期持久化存储,具备存储有效期,需要自己设置
    • 稳定性:不稳定,清除历史记录或者电脑垃圾可能会清除cookie、以及网站的隐私/无痕模式下是禁止存储cookie的
    • 与服务器的关系:cookie不是单纯的本地存储,和服务器之间有"猫腻":知道本地存储cookie,无论服务器需不需要,每一次请求都会基于请求头中的cookie字段,把存储的信息传递给服务器(如果存储东西多,导致每一次请求会变慢);服务器只要在响应头中设置set-Cookie字段,浏览器自己就会在本地设置cookie;
  • @2localStorage:
    • localStorage.setItem([key],[value]):设置一个项
    • localStorage.getItem([key]):获取一项
    • localStorage.removeItem([key]):移除某项
    • localStorage.clear():清除所有项
    • 缺点:H5中新增的API,不兼容IE6~8
    • 优点:存储内容有大小限制:同源下最多允许存储5MB
    • 有效期持久化存储,除非手动删除,否则一直存着,不具备有效期
    • 稳定性:干掉cookie的那些操作暂时都干不掉localeStorage
    • 与服务器的关系:绝对的本地存储,和服务器之间没有任何关系[可以手动把本地存储的信息传递给服务器]
  • @3 sessionStorage:
    • sessionStorage.setItem([key],[value]):设置一个项
    • sessionStorage.getItem([key]):获取一项
    • sessionStorage.removeItem([key]):移除某项
    • sessionStorage.clear():清除所有项
    • 特点:页面刷新还在,关闭页面就没了,无论是localStorage还是cookie,只要本地存储了信息,页面刷新或者页面关闭后重新打开,存储的信息都在,而sessionStore属于会话存储:页面刷新存储的信息时存在的,以为会话还没结束;但是一旦页面关闭,会话结束,则存储的信息就会释放掉。
  • @4 vuex/redux:
    • 特点页面刷新就没了,他们类似于在全局上下文中创建全局变量(或者容器)来存储信息,所以只有页面刷新或者管理,之前存储的信息都会释放。
  • @5 IndexedDB:@5和@6都是本地数据库存储,很不常用
  • @6 WebSQL:

3.DNS解析

  • 域名解析:基于域名到DNS服务器上进行查找,找到服务器的外网IP[每次解析大概需要20~120ms左右]
  • 解析步骤
    • 1、递归查询:从本地获取DNS解析记录(本地解析记录一般是缓存下来的,也有自己手动配置的)
      • 递归查询的步骤:客户端->浏览器的DNS解析缓存->本地HOSTS文件->本地DNS解析器缓存->本地DNS服务器
      • 以上只要某一步找到,就返回给客户端,如果都没找到,再进行迭代查询
    • 2、迭代查询:本地没有找到解析记录,才会去公网上查询
      • 迭代查询的步骤:根域名服务器->顶级域名服务器->权威域名服务器
      • 以上三步必须全部查询
  • 项目优化
    • 1、提高域名的解析效率/速度
      • 把资源放到相同服务器的相同服务下,确保页面中域名解析的次数少,这样的操作虽然优化了DNS的解析,但是可能导致服务器压力过大,服务处理速度变慢,导致网站整体性能更差!(所以真实项目中,我们宁愿增加域名解析次数,也会把不同的资源分散到不同的服务器上部署)
        • web服务器:处理html/css/js…静态资源
        • 数据服务器:处理ajax请求的、实现数据管控和业务逻辑的
        • 图片/音视频服务器:处理富媒体资源的
      • 在域名解析增加的情况下,我们可以基于DNS Prefetch(DNS预解析)来优化域名
        • 原理:利用link标签的异步处理,在GUI主线程渲染过程中,同时在预先完成DNS解析,这样后续到了指定资源请求的时候,DNS可能已经解析过了,此时我们从缓存中获取解析记录即可,也优化了页面渲染的速度!!

4.TCP三次握手

  • TCP三次握手(目的:建立客户端与服务器端的链接通道)(修路)

    • 通信协议:TCP[安全稳定]、UDP[快]
      • TCP:需要经历三次握手,才建立通道,虽然通道稳定,但是消耗时间
      • UDP:无需经历三次握手,直接传输,这样可能会"丢包",但是快…
  • seq序号:用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标识
    ack确认序号:只有ACK标志位为1时,确认序号字段才有效,ack=seq+1
    标志位:
    	ACK:确认序号有效
    	RST:重置连接
    	SYN:发起一个新连接
    	FIN:释放一个连接
    

5.基于HTTP建立连接

  • http事务
  • http报文:请求报文&响应报文
  • 请求方式:GET/POST/DELETE/PUT/HEAD/APTCH/OPTIONS
  • HTTP状态码:200 301 302 307 304 400 401 403 404 500 503 …
  • 请求主体&响应主体的数据格式要求…

6.TCP四次挥手

  • :TCP四次挥手【作用:把建立的链接通道释放掉
    • 如果每一请求都需要重新的TCP[三握四挥],很耽误时间也很消耗性能,我们最好保持TCP通道的持久性->"长链接"
      • 长连接:服务器在响应头中设置Connection:keep-alive,浏览器也在请求头中设置Connection:keep-alive
      • 我们可以设定长连接的周期:Keep-Alive:timeout=15,max=300

7.浏览器底层渲染

GUI渲染的几大步骤?

  • @1 生成DOM TREE【描述DOM/节点的层级关系】
  • @2 生成CSSOM TREE 【等待样式资源获取到,GUI会进行渲染,把样式按照"层叠样式表"渲染为CSSOM TREE】
  • @3 生成Render TREE【把DOM TREE 和CSSOM TREE 结合在一起,规划每个节点应该渲染的样式。后期渲染页面就是按照这个来的】
  • @3Layout布局【根据视口大小,计算每个节点在视口中的位置和大小等】
    • 如果后期的某些操作会导致视口中的节点位置,大小,或者视口大小发生改变,此时我们需要重新计算每个节点在视口中的最新位置等,我们把这个操作叫做“回流、重排(reflow)”;
  • @5 分层【按照样式,分为不同的层级(文档流),并计算出每一层文档流中的节点如何渲染】
  • @6 Painting绘制【绘制完成的结果就是在浏览器中看到页面和效果】
    • 如果后期某些节点的样式发生改变(位置和大小等不变,只是样式、背景等样式改变),浏览器需要重新按照最新的样式去绘制,我们这个操作称为"重绘 Repaint"
  • 页面第一次渲染一定会引发一次Layout布局和Painting布局
    • 后期发生重排一定会引发重绘,但重绘不一定非要重排,重排非常的消耗性能(这也是我们所谓操作DOM损耗性能的主要原因)

线程与进程?

  • 线程&进程:一个进程包含多个线程

    • 进程:一个页面,应用程序,都是一个进程
    • 线程:一个进程中有很多线程
  • 浏览器是一个进程,进程中存在多种线程:

    • GUI渲染线程:自上而下渲染HTML/CSS代码
    • JS引擎线程:解析和渲染代码
    • HTTP网络线程:从服务器获取资源和数据
    • 定时器的监听线程
    • 事件监听线程
    • 浏览器只会分配一个"JS引擎线程",js是单线程的

GUI渲染遇到不同类型标签的做法?

  • 遇到link/img…:会开辟新的HTTP线程去获取资源,GUI继续向下执行【异步
  • 遇到
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值