likes
comments
collection
share

【浏览器原理】前端应该知道的浏览器相关知识点

作者站长头像
站长
· 阅读数 13

引言

浏览器常见缓存有哪些?浏览器渲染引擎的工作原理是什么?近期整理了一些浏览器相关知识,分享给大家一起来学习。如有问题,欢迎指正。

1. Web缓存原理

什么是缓存:

第一次访问页面,服务器是原原本本把所有的数据给浏览器。

第二次访问,是没有必要把所有的资源原原本本返回,将一些请求过得静态资源( CSS/JS/ 图片)无论是存储到本地或者服务端,不再重新获取,这就是缓存。

为什么要有缓存:

CPU计算很快,页面渲染只需要毫秒,比较慢的是网络请求几百毫秒,同时网路请求存在不稳定性。

  • 减少请求次数
  • 提高页面加载速度
  • 减少服务器负担
  • 提高网站的性能

2. 强制缓存与协商缓存

强制缓存

浏览器初次请求,服务器返回资源和Cache-control(资源可以缓存,就加cache-control)再次请求,判断cache-control没有过期,没有过期,就会在本地缓存中找资源。如果过期了,再次返回资源和cache-control,重新设置。

【浏览器原理】前端应该知道的浏览器相关知识点

  • 服务器端控制,在Response Headers 中
  • 例如 Cache-Control:max-age=3153600(单位是s)

Cache-control的值

  • Max-age :设置缓存过期时间
  • No-cache:不用强制缓存
  • No-store:不用强制缓存,不用协商缓存

Expires

  • 同在响应头中
  • 同为控制缓存过期
  • 已被Cache-Control代替(存在于http1.0中)

协商缓存

如果命中强制缓存,我们无需发起新的请求,直接使用缓存内容,如果没有命中强制缓存,如果设置了协商缓存,这个时候协商缓存就会发挥作用。

服务端缓存策略(服务端判断客户端资源,是否和服务端一样)

浏览器初次请求,服务器返回资源和last-ModifiedEtag,再次请求在请求头中携带If-Modified-Since(是否修改自从)和If-none-Match(是否没有匹配),服务端进行校验,一致则返回304,否则返回200和最新资源。

Last-Modified 【浏览器原理】前端应该知道的浏览器相关知识点

Etag

【浏览器原理】前端应该知道的浏览器相关知识点

  • 在Response Header中
  • Last-Modified 资源的最后修改时间
  • Etag资源唯一标识(一个字符串)
  • 优先使用Etag,etag根据内容计算会精准一些,Modified只能精确到秒级

【浏览器原理】前端应该知道的浏览器相关知识点

二者应用场景:

对于频繁改动的文件,采用协商缓存处理,通过Etag的值来判断当前缓存是否可用。 对于基本不变化的资源,采用强制缓存处理,通过设置cache-control:max-age

3. 三种刷新有什么区别

  • 正常操作:地址栏输入url,跳转链接,前进后退
  • 手动刷新:f5
  • 强制刷新:ctrl+f5

正常操作:强制缓存、协商缓存都有效

手动操作:强制缓存失效,协商缓存有效(可能返回304或200)

强制刷新;强制、协商都失效(相当于请求从来没有来过)

4. 输入URL到页面展示的全过程

大概分三个步骤: 

网络请求

  • DNS解析:将域名解析为IP地址
  • 客户端与服务器建立TCP连接:三次握手
  • 客户端发起HTTP请求
  • 服务器处理HTTP请求

得到html源代码,遇到静态资源(css/js/图片/视频)继续请求

解析渲染

  • 浏览器根据 html 文件构建 DOM
  • 根据CSS构建CSSDOM书(style tree)
  • 两者结合,形成 render tree
  • 将Render Tree 渲染到界面

断开连接,四次挥手

【浏览器原理】前端应该知道的浏览器相关知识点 渲染过程中遇到JS文件如何处理?

遇到script暂停渲染,优先加载并执行JS代码,完成继续渲染。JS线程和和渲染线程共用一个线程。

遇到图片如何处理?

加载图片,不影响继续渲染,等图片加载完插进来。

5. 网页重绘和重排

重绘:重新绘制这个元素,当元素的样式发生改变浏览器会重新绘制这个元素

重排:重新排列这个元素,当元素位置或者结构发生改变,浏览器重新计算渲染整个DOM 。重排可能影响其他元素,消耗会大一些

  • 定位属性及浮动
positiontopbottomleftrightfloatclear
  • 盒子模型相关属性
widthheightpaddingmargindisplayborder
  • 文本相关属性
font-sizefont-weightfont-familytext-alignline-height、vertival-align、white-space

优化手段:

  • 集中修改样式,使用class
  • 使用createDocumentFragment批量操作DOM
  • 使用BFC特性,不影响其他元素位置
  • 元素位置移动变换使用 CSS3 的 transform 来代替对 top left 等的操作
  • 使用CSS中的动画

6. Window.onload和DOMContentLoaded区别

  • Window.onload 资源全部加载完成才执行,包括图片
  • DomContentLoaded  DOM渲染完成即可,图片可能尚未下载

7. 前端安全问题 如何防范

XSS

Cross Site Script 跨站脚本攻击(跨站请求攻击)

手段:攻击者将JS脚本插入到网页中,渲染时执行JS

【浏览器原理】前端应该知道的浏览器相关知识点

比如获取到你的cookies,获取你的通过img方式传给自己的服务器,因为img规避跨域的。

预防:替换特殊字符,可以把<变成&It; >变成&gt;直接显示,而不会作为脚本执行。

【浏览器原理】前端应该知道的浏览器相关知识点

工具:www.npmjs.com/package/xss

<script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script>  
<script>  
  // apply function filterXSS in the same way  
  var html = filterXSS('<script>alert("xss");</scr' + "ipt>");  
  alert(html);  
</script>

CSRF

  • Cross Site Request Forgery 跨站请求伪造
  • 手段:攻击者诱导用户去访问另一个网站的接口

登录邮箱,内容下面有个广告,点了广告,跳转了新的页面,页面什么都没有,然后你就关了。

因为你已经登录了有了cookies,当你打开了页面,访问gamail接口,自动把你的邮件转发到另一个邮箱中。(网站的api发现有cookie,认为使用户自己操作的)。诱导转发邮件,类似的还有诱导购买,诱导关注。

  • 预防:严格控制跨域+验证码限制
  1. 服务端严格跨域请求限制,判断接口来源referrer(http请求头 请求来源)
  2. 禁止跨域传递cookies,为cookies设置SameSite
  3. 关键接口加短信验证码

DDoS

  • Distribute denial-of-service分布式拒绝服务
  • 手段:分布式、大规模流量访问,使浏览器瘫痪 (一般是通过一些其他手段,散布一些病毒木马到一些手机上,控制病毒木马统一的时间去访问网站)
  • 预防:需要硬件防护(如阿里云WAF)

点击劫持 Click Jacking

  • 手段:攻击者在界面上蒙一个透明的iframe,诱导用户点击
  • 预防:让iframe不能跨域加载
  1. 设置请求x-Frame-Options:sameorigin frame页面的地址只能为同源域名下的页面

【浏览器原理】前端应该知道的浏览器相关知识点 2. 判断两个域名是否一致 在顶层页面打开的url(跳出框架)和本页面打开url

【浏览器原理】前端应该知道的浏览器相关知识点

SQL注入

  • 现在前后端分离,这种方式比较少了
  • 手段:攻击者提交内容写入sql语句,破坏数据库
  • 预防:处理输入的内容,替换特殊字符

8. 进程和线程的概念

首先,计算机的核心是CPU,他承担了所有的计算任务,他就像一座工厂,时刻运行着。

假定工厂的电力有限,一次只能供给一个车间使用,也就是说,一个车间开工的时候,其他车间必须停工。背后的含义是:单个CPU一次只能运行一个任务。

进程好比工厂的车间,他代表CPU能够处理的单个任务,任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

一个车间里,可以有很多工人,他们协同完成一个任务,线程好比车间的工人,一个进程可以包括多个线程。

车间的工人们是共享的,比如许多房间每个工人都可以进出。这象征着一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。

用专业的语言解释就是:

进程: 一个进程就是一个程序运行的实例,详细解释就是:启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码,运行中的数据和一个执行任务的主线程,我们把这样一个运行环境叫做进程。

线程: 是处理具体任务的,线程不能单独存在,它是由进程来启动和管理的。

  • 单线程:一个进程只有一个主线程
  • 多线程:一个进程中有多个线程

【浏览器原理】前端应该知道的浏览器相关知识点 从图中我们可以看到:线程是依附进程的,而进程中使用多线程并行处理能提升运算效率。

特点:

  • 进程中任意线程执行出错,都会导致整个进程崩溃
  • 线程之间共享进程中的数据
  • 当一个进程关闭后,操作系统会回收进程所占的内存
  • 进程之间的内容相互隔离

9. 多进程浏览器

早期的浏览器是单进程的,但随之Chrome浏览器的发展,衍生了多进程架构:

【浏览器原理】前端应该知道的浏览器相关知识点

浏览器主进程

  • 负责管理各个标签页的创建和销毁
  • 负责浏览器的页面显示和功能(前进,后退,收藏等)
  • 负责资源的管理与下载
  • 负责子进程的管理

渲染进程

  • 浏览器内核,主要负责HTML,CSS,JS等文件的解析和执行
  • 默认情况下,浏览器会为每一个标签页开启一个新的渲染进程,以保证不同标签页之间不会影响。

网络进程

主要负责页面的网络资源加载

GPU进程

负责3D绘制和硬件加速

插件进程

主要是负责插件的运行,每个插件使用时候都会创建一个对应的进程

10. 浏览器的渲染线程有哪些

浏览器的渲染线程总共有五种:

【浏览器原理】前端应该知道的浏览器相关知识点

GUI渲染线程

负责渲染浏览器页面,解析html、css,构建dom树,CSSOM树,render树。

JS引擎线程

JS引擎线程也称为JS内核,负责处理JS脚本程序,解析脚本,运行代码。

定时器触发线程

  • 计时器触发线程即setInterval和setTimeout所在线程
  • W3C 在 HTML 标准中规定,定时器的定时时间不能小于 4ms,如 果是小于 4ms,则默认为 4ms。

事件触发线程

事件触发线程用来控制事件循环

异步HTTP请求线程

XMLHttpRequest连接后通过浏览器开一个线程请求

11. JS为什么是单线程

  • JS作为浏览器脚本语言,主要用途是与用户互动,以及操作DOM。
  • 这是JS语言特征决定,否则会带来很复杂的同步问题 比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
  • HTML5 提出Web Worker标,允许JS脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM,这并没有改变JS单线程的本质。

12. 僵尸进程和孤儿进程是什么

僵尸进程:子进程比父进程先结束, 而父进程又没有释放子进程占用的资源,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵死进程。

孤儿进程:父进程退出了, 而它的一个或多个进程还在运行,那这些子进程都会成为孤儿进程。

13. Cookie与session区别

HTTP请求是无状态的,客户端无法识别两个请求是否来自同一客户端。cookie和session用来识别用户身份,实现对话控制。

cookie

  • 服务端向客户端set-cookie,客户端每次请求带着cookie
  • cookie存储着用户标识
  • 默认有跨域限制:不跨域共享,不跨域传递

 Session

  • Cookie+session是常见的登录验证解决方案
  • Session存储于服务端的一个对象,存储用户详细信息,和cookies一一对应

二者区别主要有以下四点:

  • 存储位置:cookie存储客户端于临时文件夹中。session存储在服务器内存中。

  • 安全性:Cookie 以明文的方式存储在客户端,安全性低,从可通过加密算法进行加密。session存储在服务器内存中,安全性较高。

  • 大小:cookie数量大小有限制,数量不超过50 个,单个大小<4kb。session保存数据没有限制,内存有多大就能有多大。

  • 生命周期:cookie的生命周期是累计的,创建时,开始计时,时间到,生命周期结束。 session的生命周期是间隔的,从创建时,就开始计时,期间无访问,销毁,有访问,重新计算,关机会造成session生命周期结束。  

14. Cookie和token区别

  • Cookie是HTTP规范,随着请求自动传递,token需要自己加上
  • Cookie会默认被浏览器存储,token需要自己存储(storage)
  • Token默认没有跨域限制

15. 常见的前端登录方案

Cookie和session

  • 浏览器输入用户名密码,服务端校验,通过后把用户信息写入session
  • 服务器通过set-cookie(用户标识)给浏览器
  • 浏览器访问其他接口时候带着cookie,服务端根据cookie去session中去拿,定位用户信息。

【浏览器原理】前端应该知道的浏览器相关知识点

JWT( JSON web token)

  • 前端登录,登录成功后,后端返回加密token
  • 前端自行存储token(其中包含了用户信息,加密了)
  • 以后请求都带着token,作为用户信息

【浏览器原理】前端应该知道的浏览器相关知识点

16. Session 和JWT哪个更好

Sesison优点

  • 原理简单,易于学习
  • 用户信息存储在服务端,可快速封禁某个用户

Session缺点

  • 占用服务端内存,硬件成本高
  • 多进程,多服务器时,不好同步,须使用第三方缓存,如reids
  • 默认有跨域限制

JWT优点

  • 不占用服务端内存
  • 多进程、多服务不受影响
  • 没有跨域限制

JWT缺点

  • 用户信息存储在客户端,无法快速封禁用户
  • 万一客户端密钥被泄露,用户信息会全部丢失
  • Token体积一般会比cookie会增加数据请求量

适用场景

  • 如果有严格的信息管理需求( 保密、快速封禁)推荐Session
  • 如果没有特殊要求,建议使用JWT(如初创型网站)

17. localStorage和sessionStorage区别

localStorage和sessionStorage都是H5新增本地存储方式;本质是一个hash表。

目的解决cookie存储空间不足问题,每个只能最大只能存4kb,每个 domain限制20个cookie,而storage可以存储5M-10M。 主要区别如下:

生命周期

  • localStorage的生命周期是永久的,除用户手动清除浏览器缓存。
  • sessionStorage生命周期仅在当前会话有效,当标签页关闭会被清除。

作用域

  • localStorage的作用域是在同一浏览器,可以共享localStorage数据。
  • sessionStorage的作用域是在同一浏览器且同一窗口共享localStorage数据。

18. Cookies和localStorage能跨域吗

Cookies默认是不支持跨域 ,但是在二级域名是可以共享cookie的,实现单点登录。

Localstorage默认也是不支持跨域的,只有当一个页面通过iframe嵌入到另一个页面中,并且这两个页面具有相同的源时,它们可以共享localStorage。

19. 如何实现页面多标签通讯

Websocker

  • 无跨域限制,需要服务端支持,成本高
  • 客户端发消息给客户端,客户端再往下同步到其他页面

LocalStorage

  • A页面设置localstorage,B页面监听localstorage值变化
<!--Eg:列表页,详情页 (点击修改标题按钮,同步到列表页)-->
<!--详情页-->
<body>
    <button id="btn1">修改标题</button>
</body>
<script>
    const btn1 = document.getElementById('btn1');
    btn1.addEventListener('click',()=>{
        const newInfo ={
            id:100,
            name:'标题'+Date.now()
        }
      localStorage.setItem('change',JSON.stringify(newInfo))
    })
</script>
<!--列表页-->
<script>
    // 当storage的值发生变化时候会触发
    window.addEventListener('storage',()=>{
        console.log(event.key) //change
        console.log(JSON.parse(event.newValue)) // {id: 100, name: '标题1693969577645'}
    })
</script>

SharedWork

  • SharedWorker是webWorker的一种
  • webWorker可开启子进程执行JS,但不能操作DOM
  • SharedWorker可单独开启一个进程,用于同域页面通讯
  • 调试不方便,不支持ie11

20. 如何实现页面和iframe间通讯

postMessage

<!--父元素:使用window.iframe1.contentWindow.postMessage进行发送信息-->
<body>
    <button id="btn1">发送消息</button>
    <iframe id="iframe1" src="./child.html"></iframe>
</body>
<script>
  const btn1 =document.getElementById('btn1');
     btn1.addEventListener('click',()=>{
        // 发送消息 是否域名限制
        window.iframe1.contentWindow.postMessage('hello','*')
     }) 

     // 接收信息
     window.addEventListener('message',event=>{
       // 来源域名信息
       console.log(event.origin)
       console.log(event.data)
     })
</script>
<!--子元素:使用message事件接收信息-->
<body>
    <button id="btn1">发送消息</button>
</body>

<script>
     const btn1 =document.getElementById('btn1');
     btn1.addEventListener('click',()=>{
        window.parent.postMessage('world','*')
     })
    // 接收信息
    window.addEventListener('message',event=>{
       // 来源域名信息
       console.log(event.origin)
       console.log(event.data)
     })
</script>

21. 对浏览器的理解

浏览器的主要功能是将用户选择的web资源呈现出来,它先是从服务器请求资源,然后将其展示在浏览器窗口中,资源的格式通常是HTML,也包括PDF、image及其他格式。用户用URL来指定所请求资源的位置。

HTML和CSS规范中规定了浏览器解释html文档的方式,由W3C这个组织对这些规范进行维护,W3C是指定web标准的组织。但是浏览器厂商会扩展,不严格遵循规范标准,这为web开发者带来了严重的兼容问题。

浏览器可以分为两部分,shell和内核。

  • shell:是指浏览器的外壳,例如:菜单,工具栏等。主要是提供给用户界面操作,参数设置等。它是调用内核来实现各种功能。
  • 内核:是浏览器的核心,内核是基于标记语言显示内容的程序和模块。

浏览器内核主要分为两部分:

  • 渲染引擎:渲染引擎的职责就是渲染,默认情况下,渲染引擎可以显示html文档及图片,也可以借助插件展示其他的类型数据,比如:借助pdf阅读器,显示pdf格式。
  • JS引擎:解析和执行JS来实现网页动态效果。

最开始渲染引擎和JS引擎没有区分很明确,后来JS引擎越来越独立,内核就倾向于指渲染引擎。

22. 常见浏览器内核比较

浏览器内核有四种,分别是:IE(trident)火狐(gecko)苹果和欧朋的(webkit)谷歌(blink)

  • Trident

微软早起官方自带浏览器是IE,占据大量的市场份额,比较流行,后期微软长时间不更新,就导致了Trident和W3C标准脱节,还有本身存在很多bug和安全问题,现在使用的已经越来少少了。

  • Gecko

火狐浏览器采用的内核,接口十分丰富,缺点也很明显,耗费资源和内存

  • Webkit

Safari苹果采用的内核,优点就是页面渲染速度比较快,缺点就是兼容性不是很好,编写一些不标准的网页无法正确显示

  • Blink

是 Webkit 的一个分支。是谷歌与欧朋共同研发,后面Opera 弃用了自己的 Presto 内核,加入 Google 阵营,跟随谷歌一起研发 Blink。

23. 浏览器同源策略

  • ajax请求中,浏览器要求网页和服务端接口必须同源(安全)
  • 同源:协议、域名、端口三者必须一致
  • 加载图片、CSS、JS可无视同源策略
<img src="跨域的图片地址">
<link href ="跨域的css地址">
<script src="跨域的JS地址"></script>
  • 所有的跨域,都必须经过服务端允许和配合

同源政策主要限制了三个方面:

  • 当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB。
  • 当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。
  • 当前域下 ajax 无法发送跨域请求。

24. 如何解决跨域问题

JSONP

  • script标签天然具有跨域能力
  • 服务端拼接信息
  • 具有局限性, 仅支持get方法

【浏览器原理】前端应该知道的浏览器相关知识点

CROSS

【浏览器原理】前端应该知道的浏览器相关知识点

proty

通过代理,将前端发的浏览器请求转化为服务器向服务器的请求。

devServer:{
    proxy:{   
   // 发送的路径 http://127.0.0.1/user/login
   // 本地 http://localhost:8080/api/user/login
        
   // 检查本地所有以/api开头的请求路径,将api前面的路径改为target路径  
   // 发送路径无api,替换成空串。
   '/api':{
    target:" http://127.0.0.1",
    // 这一步完成后: http://127.0.0.1/api/users/info
    pathRewrite:{'^/api': ""}, // 路径重写,如果路径以api开头,替换为空串
    // http://localhost:4000/users/info
    changeOrigin:true // 支持跨域
   }
 }
}

nginx代理跨域

#proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;
        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}
  • node中间件代理
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', proxy({
    // 代理跨域目标接口
    target: 'http://www.domain2.com:8080',
    changeOrigin: true,
    // 修改响应头信息,实现跨域并允许带cookie
    onProxyRes: function(proxyRes, req, res) {
        res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');
        res.header('Access-Control-Allow-Credentials', 'true');
    },
    // 修改响应信息中的cookie域名
    cookieDomainRewrite: 'www.domain1.com'  // 可以为false,表示不修改
}));
app.listen(3000);
console.log('Proxy server is listen at port 3000...');

前端直接调用

"login": [ function (cb, result) {
  trainingcamp.login({phone,typecode,verify}, function (data) {
    cb(null, data);
  });

}],
  
  login: function (d, cb) { // 登陆
    console.log("---------这个是给后端接口的,再看看-------")
    console.log(d)
    api({
      port: "CLASSWAPAPI",
      path: "/passport/user/getphonelogincode",
      method: 'post',
      data: d
    }, cb);
  }
}