第一章 浏览器运行原理
1. 浏览器发展史
2. 浏览器结构
- 用户界面:用于展示除标签页窗口外的其他用户界面内容
- 浏览器引擎:用于在用户界面和渲染引擎之间传递数据
- 渲染引擎:负责渲染用户请求的 页面内容
渲染引擎是浏览器的重要组成部分,也被称为浏览器的内核。不同浏览器的内核也不相同,以目前主流的谷歌浏览器为例讲解浏览器的运行原理。
3. 浏览器运行原理
讲解浏览器运行原理前,需要了解两个概念:进程和线程
- 进程
进程是操作系统进行资源分配和调度的基本单元,可以申请和拥有计算机资源。进程是程序的基本执行实体。
- 线程
线程是操作系统能够进行运算调度的最小单位,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
浏览器根据不同的功能可以划分为多个进程,示意图如下所示:
- 浏览器进程:控制除标签页外的用户界面,包括前进、后退、书签、地址栏等
- 缓存进程:负责缓存数据
- 网络进程:发起接受网络请求
- GPU进程:负责整个浏览器界面的渲染
- 插件进程:负责控制网站使用的所有插件
- 渲染器进程:控制显示tab标签内的所有内容,默认会为每个标签页都创建一个进程,可以通过浏览器的进程模式修改
以地址栏输入内容为例进行逻辑梳理,流程如下:
1️⃣:浏览器进程的UI线程会捕捉地址栏的输入内容
- 输入为网址:UI线程会启动一个网络线程,请求
DNS进行域名解析并连接服务器获取数据 - 输入非网址:利用配置的默认搜索引擎进行关键字查询
2️⃣:网络线程获取到数据后,会通过SafeBrowsing(谷歌内部的站点安全系统)进行检查站点,判断是否为恶意站点
- 恶意站点:浏览器会弹出警告页面,阻止用户继续访问
- 非恶意站点:网络线程会将数据传递给UI线程,进行下一步操作
3️⃣:UI线程会创建一个渲染器进程来渲染页面。浏览器进程会通过IPC管道将数据传递给渲染器进程的主线程,正式进入渲染流程
4️⃣:渲染器进程的主线程拿到html数据后,分别将html、js、css、image等解析执行
构造DOM树:html首先经过tokeniser标记化,通过词法分析将输入的html内容解析成多个标记。然后根据标记内容构造DOM树,在构造过程中会创建document对象,并以document为根节点的DOM不断进行修改,添加或删除各种元素样式计算:将css样式表进行解析,并和DOM树生成的document结构进行合并,应用样式。css、image等资源需要从网络或者缓存中读取,该操作不会阻塞html的解析过程解析和执行js脚本:在解析html过程中遇到js脚本,会阻塞html的解析,转而去解析和执行js脚本layout布局:主线程通过遍历DOM和计算好的样式生成Layout Tree,Layout Tree记录了每一个节点的坐标和边框尺寸,并且Layout Tree不会包含“display:none”的节点Paint:主线程遍历Layout Tree,创建一个绘制记录表Paint Record,该表记录了绘制的顺序Layer Tree:主线程遍历绘制记录表Paint Record,生成Layer Tree
5️⃣:主线程将绘制记录表Paint Record和Layer Tree传递给合成器线程,合成器线程按照规则进行图层划分,并把单个图层切割为更小的图块,并将图块传递给栅格化线程
划分图层:页面上的各个元素按照一定的规则进行图层划分
6️⃣:栅格化线程将每个图块进行栅格化,并存储在GPU内存中
栅格化图层:将划分的每一个图层都进行栅格化
7️⃣:栅格化完成后,合成器线程会收集栅格化线程返回的“draw quads”的图块信息,该信息包含图块在内存中的位置和在页面的绘制位置,根据图块信息合成一个合成器帧,并通过IPC传递给浏览器进程
组合图层:将可视区域内的图层组合成一帧进行展示
8️⃣:浏览器进程将合成帧传递到GPU进程,GPU进程负责将其渲染到屏幕上
当改变一个元素的位置、大小等几何信息时,会重新进行样式计算、布局、绘制及后面所有流程,这个现象被称为重排。
当改变一个元素的颜色属性时,不会重新进行布局,但是会触发样式计算和绘制,这个现象被称为重绘。
重排重绘和JS的解析执行都会占用渲染器的主线程,当同时存在JS脚本和频繁的重排重绘时,当绘制完一帧后,如果有空余时间,主线程会去执行JS脚本,如果JS脚本执行时间过长会导致没有及时归还主线程,则会出现动画绘制延迟,即页面卡顿现象。
针对此问题有两种优化方式,分别如下:
-
requestAnimationFrame():该方法的调用频率是一帧,浏览器会将JS脚本分割为多个小的任务块,在每一帧时间用完之前暂停JS执行,归还主线程。这样可以保证下一帧的绘制不会被延迟,造成页面卡顿。该方式同React Fiber的优化原理一致 -
Transform:Transform属性实现的动画不会经过布局和绘制,直接运行在合成器线程和栅格化线程中,不会受到主线程中JS脚本的影响。- Position:通过transform:translate(x,y)代替
- Scale:通过transform:scale(x,y)代替
- Rotation:通过transform:rotate(deg)代替
4. CPU和GPU
- CPU 中央处理器
一个cpu可以看成是计算机的大脑。一个cpu内核,可以想象成一个办公室工作人员,可以处理一个接一个的工作。
过去大多数的cpu都是单芯片,现代硬件中,通常会有多内核,为手机和电脑提供强大的计算能力。
- GPU 图形处理器(显卡)
处理与其他进程隔离的GPU任务,主要用于图形处理。
优点:
- 利用GPU可以渲染流畅的3D动画效果,不会造成浏览器的CPU占用率和能耗过高
- Chrome将 GPU 加速运用到了video、canvas等标签的渲染上
- 使用图像合成的方式高效合成Z轴方向重叠元素
利用GPU提升性能:
- 将纯栅格化的任务交给GPU,降低绘制使用时间
- 利用合成器,让一些动画完全在GPU中绘制,减少CPU的使用
- 图层之间互不影响
面向GPU的页面编程:
-
WebGL:WebGL是OpenGL的子集,利用WebGL可以实现复杂的图像处理,如边缘查找、裁剪、滤镜等。WebGL是浏览器与GPU最直接的沟通方式;
-
canvas:通过canvas.getontext('webgl)可获取到WebGL渲染上下文,访问丰富的WebGL功能;
-
GPU强大的浮点运算和并行运算的能力,可以分担一些需要CPU来完成的大规模的计算问题,如密码破解、数据压缩;
第二章 BOM对象
“Brower Object Model”浏览器对象模型。浏览器对象指浏览器提供的一系列内置对象的统称,BOM浏览器对象模型即为各内置对象之间按照某种层次组织起来的模型的统称。
BOM对象用来操作浏览器窗口及窗口上的控件,实现用户和页面的动态交互。
window对象是BOM的顶层(核心)对象,其他的对象都是以属性的方式添加到window对象下,也可称为window的子对象。
1. window
全局作用域,定义在全局作用域中的变量、函数以及JavaScript中的内置函数都可以被window对象调用。
1)属性
| 属性名 | 说明 |
|---|---|
| closed | 窗口是否关闭 |
| name | 窗口名称 |
| opener | 对创建该窗口的window对象的引用 |
| parent | 当前窗口的父窗口 |
| self | 当前窗口,等价于window属性 |
| top | 最顶层的父窗口 |
2)方法
| 方法名 | 说明 |
|---|---|
| alert() | 弹出警告框 |
| confirm() | 弹出对话框 |
| prompt() | 弹出对话框 |
| open() | 打开一个新的浏览器窗口或查找一个已命名的窗口 |
| close() | 关闭窗口 |
| focus() | 把键盘焦点聚焦在某个窗口 |
| print() | 打印当前窗口的内容 |
| scrollBy() | 按照指定的像素值滚动当前窗口内容 |
| scrollTo() | 把当前窗口内容滚动到指定的坐标 |
| resize() | 浏览器窗口大小改变的事件 |
3)窗口位置和大小
| 属性 | 说明 |
|---|---|
| screenLeft | 相对于屏幕窗口的x坐标(Firefox不支持) |
| screenTop | 相对于屏幕窗口的y坐标(Firefox不支持) |
| screenX | 相对于屏幕窗口的x坐标(IE8不支持) |
| screenY | 相对于屏幕窗口的y坐标(IE8不支持) |
| innerHeight | 窗口文档显示区的高度(IE8不支持) |
| innerWidth | 窗口文档显示区的宽度(IE8不支持) |
| outerHeight | 窗口的外部高度,包含工具条与滚动条(IE8不支持) |
| outerWidth | 窗口的外部宽度,包含工具条与滚动条(IE8不支持) |
| moveBy() | 将窗口移动到相对的位置 |
| moveTo() | 将窗口移动到指定的位置 |
| resizeBy() | 将窗口大小调整到相对的宽度和高度 |
| resizeTo() | 将窗口大小调整到指定的宽度和高度 |
4)定时器
| 方法名 | 说明 |
|---|---|
| setTimeout() | 在指定的毫秒数后调用函数或执行一段代码 |
| setInterval() | 按照指定的周期(以毫秒计)来调用函数或执行一段代码 |
| clearTimeout() | 取消由setTimeout()方法设置的定时器 |
| clearInterval() | 取消由setInterval()设置的定时器 |
2. document
文档对象或DOM对象,是HTML页面当前窗体的内容,也是JavaScript重要组成部分之一。
1)事件流
事件流包括三个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段
- 首先发生的是事件捕获,为截获取事件流提供机会
- 其次是实际的目标接收到事件
- 最后是冒泡阶段,可以在这个阶段为事件作出响应
2)事件冒泡
由目标元素开始,到最外层元素位置,逐级触发事件的过程,该过程事件执行。
div->body->html->document
3)阻止冒泡方法
e.stopPropagation;
stopPropagation();
4)事件捕获
从最外层元素开始,到目标元素为止,逐级接收事件的过程,该过程事件不执行。
document->html->body->div
5)事件委托
将目标元素的事件委托给父元素去操作,利用的是事件冒泡的原理。
不在目标元素上设置监听函数,而是在父元素上设置监听函数,通过事件获取的e判断是否为目标元素。父元素可以监听到子元素上事件的触发,通过判断事件发生元素的类型,来做出不同的响应click、mousedown、mouseup、keydown、keypress.
// 获取具体的目标元素
e.target;
// 当前正在处理事件的元素,可能是目标元素、父级元素或祖先元素
e.currentTarget;
在事件冒泡时,事件会从目标元素开始向上冒泡到其父级元素,依次触发每个元素的事件处理程序,此时e.target表示的是触发事件的目标元素,而e.currentTarget表示的是当前正在处理事件的元素,可能是父级元素或其他祖先元素。
3. location
地址栏对象,获取当前浏览器中URL地址栏内的相关数据。
1)更改URL
URL:Uniform Resource Locator,统一资源定位符
| 方法名 | 说明 |
|---|---|
| assign() | 载入一个新的文档 |
| reload() | 重新载入当前文档 |
| replace() | 用新的文档替换当前文档 |
2)获取及设置URL参数
// 获取URL的指定部分
location.属性名
// 设置URL的指定部分
location.属性名 = 值
| 参数名 | 说明 |
|---|---|
| hash | URL中#后面的内容,如果没有#,返回空 |
| pathname | 路径名 |
| host | 主机名和端口 |
| port | 端口号 |
| hostname | 主机名 |
| protocol | URL协议 |
| href | 完整的URL |
| search | URL 中的查询字符串部分 |
4. history
历史对象,记录浏览器的访问历史记录,实现浏览网页的前进与后退功能。
1)前进及后退
- length:历史记录中的网址数量
- back():加载history列表中的前一个URL,后退
- forward():加载history列表中的下一个URL,前进
- go():参数number,加载history列表中的某个具体页面
当go()方法的参数为1或-1时,与forward()和back()方法的作用相同
2)无刷新更改URL地址
- pushState():改变浏览器的历史列表中记录的数量
- replaceState():仅用于修改历史记录,历史记录列表的数量不变,与location.replace()方法的功能类似
pushState(state, title[, url]) // 添加历史记录
replaceState(state, title[, url]) // 修改历史记录
state:一个与指定网址相关的状态对象,此处可以填null或空字符串
title:新页面的标题,可以填null或空字符串
url:新的网址,并且必须与当前页面处在同一个域中
5. navigator
浏览器对象,获取浏览器的相关数据,如浏览器的名称、版本等。
属性
| 属性名 | 说明 |
|---|---|
| appCodeName | 浏览器的内部名称 |
| appName | 浏览器的名称 |
| appVersion | 浏览器的平台和版本信息 |
| cookieEnabled | 浏览器中是否启用cookie的布尔值 |
| platform | 运行浏览器的操作系统平台 |
| userAgent | 由客户端发送服务器的User-Agent头部的值 |
| onLine | 布尔值,是否联网 |
方法
| 方法名 | 说明 |
|---|---|
| javaEnabled() | 是否在浏览器中启用Java |
| ononline() | 联网时触发 |
| onofline() | 未联网时触发 |
6. screen
屏幕对象,获取与屏幕相关的数据,如屏幕的分辨率等
1)属性
| 属性名 | 说明 |
|---|---|
| height | 屏幕的高 |
| width | 屏幕的宽 |
| availHeight | 浏览器窗口在屏幕上可占用的垂直空间 |
| availWidth | 浏览器窗口在屏幕上可占用的水平空间 |
| colorDepth | 屏幕的颜色深度 |
| pixelDepthZ | 屏幕的位深度/色彩深度 |
第三章 浏览器缓存
1. 缓存分类
| 获取资源形式 | 状态码 | 发送请求到服务器 |
|---|---|---|
| 强缓存 | 200(from cache) | 否,直接从缓存取 |
| 协商缓存 | 304(not modified) | 是,通过服务器来告知缓存是否可用 |
1)二者区别
强缓存命中的话不会发请求到服务器。
协商缓存⼀定会发请求到服务器,通过请求⾸部字段验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的实体,⽽是通知客⼾端可以从缓存中加载这个资源 304。
2)属性设置
Cache-Control:请求头和响应头中都可以设置该属性
- max-age:相对时间,缓存最大的有效时间,有效时间内不会向服务器发送请求
- s-maxage:缓存最大的有效时间,有效时间是针对CDN而言,不是从浏览器读取缓存,而是从CDN读取缓存
- no-cache:始终会向服务器发送请求,由服务器判断浏览器的缓存是否过期
- no-store:对于该资源文件不使用任何缓存策略
Expires:设置缓存的过期时间,是服务器上面的一个具体的过期时间点,在过期时间前,浏览器不必向服务器发送请求,可以直接从缓存中读取资源,其优先级比max-age、s-maxage低
Last-Modified / If-Modified-Since:基于客户端和服务端协商的缓存机制
- Last-Modified:响应头
- If-Modified-Since:请求头
需要搭配Cache-Control 使用,max-age未过期则使用浏览器缓存,过期了则根据Last-Modified判断服务器上面的资源是否过期
- 304:缓存未过期
- 200:缓存过期
Etag/If-None-Match:etag是文件内容的hash值,文件内容改变则Etag改变,浏览器获取的If-None-Match与服务端返回的Etag值是否相同,相同则资源未改变,返回304,使用缓存;不同则资源改变,返回200和新的资源
- Etag:响应头
- If-None-Match:请求头
etag比Last-Modified更精确,判断的标准是文件内容,优先级⽐Last-Modified⾼
2. 缓存控制
通过设置响应头以及请求头来控制缓存策略
1)强缓存
强缓存可以通过设置 Expires 和 Cache-Control 两种响应头实现。如果同时存在, CacheControl 优先级⾼于 Expires,强缓存的特点是满足有效期内不会向服务器发送请求,即使服务器上面的资源已经更新
- Expires(响应)
含义:资源的过期时间,在过期时间之前可以直接从浏览器缓存 中存取数据 取值:绝对时间,受时差的影响 特点:如果在 Cache-Control 中设置了 max-age 或者 s-maxage 指令,那么 Expires 会被忽略
- Cache-Control(请求或者响应)
含义:资源缓存的最⼤有效时间,在该时间段内,客⼾端不需要向服务器发送请求 取值:相对时间,不受时差影响 特点:优先级⾼于 Expires
2)协商缓存
协商缓存可以通过 Last-Modified / If-Modified-Since 和 ETag / If-None-Match 这两对 Header 来控制
- Last-Modified(响应)、If-Modified-Since(请求)
含义:⽂件的最后修改时间 取值:GMT 格式的时间字符串 当带着 If-Modified-Since 请求头去服务器请求资源时,服务器会检查 Last-Modified ,如果 Last-Modified 的时间早于或 等于 If-Modified-Since 则会返回⼀个不带主体的 304 响应,否则将重新返回资源
- Etag(响应)、If-None-Match
ETag:响应⾸部字段,根据实体内容⽣成⼀段hash字符串,标识资源的状态
If-None-Match:条件式的请求⾸部,如果请求资源时在请求⾸部加上这个字段,值为之前服务器端返回的资源上的ETag ,则当且仅当服务器上没有任何资源的ETag属性值与这个值相同时,服务器才会返回请求资源实体的200响应,否则服务器会返回不带实体的304响应
ETag 优先级⽐Last-Modified⾼,同时存在时会以ETag为准
3. 强缓存分类
Chrome会根据本地内存的使用率来决定资源缓存位置,如果内存使用率低,放在磁盘里面;如果内存使用率高,放在内存里面
1)from memory cache(内存缓存)
不访问服务器,⼀般已经加载过该资源且缓存在内存中,直接从内存中读取缓存。浏览器关闭后,数据将不存在(资源被释放掉了),再次打开相同的⻚⾯时,不会出现from memory cache
2)from disk cache(硬盘缓存)
不访问服务器,已经在之前的某个时间加载过该资源,直接从硬盘中读取缓存,关闭浏览器后,数据依然存在,此资源不会随着该⻚⾯的关闭⽽释放掉,下次打开仍然会是from disk cache
3)304 Not Modified
访问服务器,发现数据没有更新,服务器返回此状态码,然后从缓存中读取数据
4. 缓存特点
1)内存缓存(from memory cache)
- 快速读取
- 时效性
2)硬盘缓存(from disk cache)
- 读取复杂
- 速度⽐内存缓存慢
5. 缓存读取顺序
- 先查找内存,如果内存中存在,从内存中加载
- 如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载
- 如果硬盘中未查找到,那就进⾏⽹络请求
- 加载到的资源缓存到硬盘和内存
6. 缓存策略
7. 用户行为对缓存的影响
- 地址栏回车跳转链接、新开窗口、浏览器前进与后退:强缓存(Expires 和 Cache-Control )和协商缓(Last-Modified 和 ETag )存均有效
- F5刷新页面:强缓存无效,协商缓存有效
- Ctrl+F5刷新页面:强缓存和协商缓存均无效
8. 设置不缓存的方式
- html文件设置meta
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate">
<meta http-equiv="expires" content="Wed, 26 Feb 1997 00:00:00 GMT">
- 服务端响应添加Cache-Control:no-cache,must-revalidate指令
- 修改请求头If-modified-since:0或If-none-match
- 请求url后增加时间戳
- 服务端设置Cache-Control:private指令,防止代理服务器缓存资源
第四章 浏览器本地存储
1. Cookie
Cookie存储小型的文本文件,使用JavaScript可以读取和写入。主要用于浏览器和服务器的交互、浏览器存储少量数据。
1)Cookie特点
- 每次HTTP请求中自动发送到服务器
- 存储容量有限,通常不超过4KB
- 受浏览器设置的限制
2)Cookie使用
name=value的结构,name和value都为字符串,Cookie默认不支持中文,只能包含ASCII字符,所以Cookie需要对Unicode字符进行编码,否则会出现乱码
3)Cookie实现原理
- 客户端首次访问服务器时,发送的请求未携带Cookie
- 服务器看到请求中未携带Cookie,在响应头中加入Set-Cookie
- 浏览器收到Set-Cookie后,会将Cookie保存下来
- 下次访问时,请求头中会携带Cookie
4)Cookie生命周期
Cookie是有生命周期的,在设置Cookie值时,可以同时设置有效期,当超过有效期后,Cookie便会失效,前端请求时,不会携带过期的Cookie
2. sessionStorage
HTML5提供的会话级别的存储机制,适用于临时保存会话数据,比如在同一浏览器选项卡或窗口之间共享数据
1)特点
- 浏览器会话结束后数据会被清除
- 在同源窗口中始终存在
- 大小为5MB左右
- 只存储字符串类型数据
- 仅在客户端使用,不能和服务端进行通信
- 接口封装较好,容易上手
2)使用
// 存储
sessionStorage.setItem(key,value)
// 获取
sessionStorage.getItem(key)
// 移除
sessionStorage.removeItem(key)
// 清空
sessionStorage.clear()
3)生命周期
- 当前浏览器窗口关闭,数据销毁
- 当前浏览器窗口刷新,在当前窗口改变URL进入同源的另一个页面时数据依然存在
- 同时打开的多个相同或同源页面sessionStorage相互独立
3. localStorage
HTML5提供的持久化的本地存储机制,用于浏览器存储数据。
允许在浏览器中存储大量的数据,5MB或更大,一般用于判断用户是否已登录,页面语言等,不要存储敏感或重要的信息,容易泄漏
1)特点
- 浏览器关闭,当前页面数据保持不变,再次打开页面时数据依然存在
- 只存储字符串类型数据
- 仅在客户端使用,不能和服务端进行通信
2)使用
// 存储
localStorage.setItem(key,value)
// 获取
localStorage.getItem(key)
// 移除
localStorage.removeItem(key)
// 清空
localStorage.clear()
3)生命周期
- 关闭页面或浏览器,数据不会销毁
- 销毁数据需要主动删除
- 同源页面数据共享
4)设置过期时间
第一步:记录存储数据的时间,并设置过期时间
第二步:过期 = 当前时间 - 存储时间 > 过期时间,未过期 = 当前时间 - 存储时间 <= 过期时间
第三步:过期则删除本地存储
// 存储 数据+时间
function setlocalstorage(key, data) {
let FirstTime = new Date().getTime();
localStorage.setItem(
key,
JSON.stringify({
data,
time: FirstTime,
})
);
}
// 获取 数据+时间
function getlocalstorage(key, Exp) {
let data = localStorage.getItem(key);
let newdata = JSON.parse(data);
if (!data) {
return;
}
// 判断是否超过过期时间
if (new Date().getTime() - newdata.time > Exp) {
localStorage.removeItem(key);
return;
}
}
4. IndexedDB
一种高级的客户端数据库,用于在浏览器中存储结构化数据,提供了事务性的存储机制和丰富的查询功能,适用于需要存储大量结构化数据或进行复杂查询的场景
1)indexedDB特点
- 非关系型数据库(NoSql)
- 支持异步操作
- 可以持久化存储数据
- 受同源策略的限制
2)indexedDB使用
let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if (!indexedDB) {
console.log("浏览器不支持indexedDB");
}
// 打开数据库
let request = indexedDB.open("MyTestDatabase");
// 创建对象仓库
request.onupgradeneeded = function (event) {
var db = event.target.result;
var objectStore = db.createObjectStore("userInfo", {keyPath: "id"});
objectStore.createIndex("name", "name", {unique: false});
objectStore.createIndex("email", "email", {unique: true});
};
// 新增数据
request.onsuccess = function (event) {
db = event.target.result;
var transaction = db.transaction(["userInfo"], "readwrite");
var objectStore = transaction.objectStore("userInfo");
for (let i of arr) {
objectStore.add(i);
}
};
// 查找数据
request.onsuccess = function (event) {
db = event.target.result;
var transaction = db.transaction(["userInfo"]);
var objectStore = transaction.objectStore("userInfo");
let men1 = objectStore.index("email");
// 查找邮箱为‘5@qq.com’的用户
men1.get('5@qq.com').onsuccess = function (e) {
var data = e.target.result;
console.log(data);
};
};
// 修改数据
request.onsuccess = function (event) {
db = event.target.result;
var transaction = db.transaction(["userInfo"], "readwrite");
var objectStore = transaction.objectStore("userInfo");
let men1 = objectStore.get(1);
men1.onsuccess = function (e) {
// 获取我们想要更新的数据
var data = e.target.result;
data.name="张三2"
console.log(data)
objectStore.put(data)
};
};
// 删除数据
request.onsuccess = function (event) {
db = event.target.result;
var transaction = db.transaction(["userInfo"], "readwrite");
var objectStore = transaction.objectStore("userInfo");
let men1 = objectStore.delete(1);
men1.onsuccess = function (e) {
console.log("删除成功")
console.log( e)
};
};
// 关闭数据库
function closeDB(db) {
db.close();
}
// 删除数据库
function deleteDBAll(dbName) {
let deleteRequest = window.indexedDB.deleteDatabase(dbName);
deleteRequest.onerror = function (event) {
console.log("删除失败");
};
deleteRequest.onsuccess = function (event) {
console.log("删除成功");
};
}
5. 四者对比
相同点:均存储在浏览器
| 不同点 | Cookie | sessionStorage | localStorage | indexedDB |
|---|---|---|---|---|
| 是否传递给服务器 | 是 | 否 | 否 | 否 |
| 大小 | 4KB | 5MB | 5MB | 250MB |
| 生命周期 | 时间或会话限制 | 当前浏览器窗口打开有效 | 永久有效,除非手动删除 | 永久有效,除非手动删除 |
| 是否同源共享 | 同源窗口共享 | 通过A页面打开的B页面会进行源网页sessionStorage复制,在B页面中可以访问到A页面数据,但是两个页面数据不共享 | 同源窗口共享 | 同源窗口共享 |
6. session与Token
1)session
Session是基于Cookie实现的,用于跟踪用户与网站的交互。在一个会话期间,服务器会为用户创建一个唯一的标识符(Session ID),将其存储在服务器的内存中。
Session主要用于存储用户的状态信息和敏感数据,如登录状态、购物车内容等,服务器可以根据标识符快速检索用户的会话数据
2)CSRF Token
浏览器自定义的令牌,一般存储在localStorage中,发送请求时会添加到请求头中,服务器会对token进行校验,不需要搭配session使用。
其特点是支持跨域访问、无状态、不需要考虑CSRF,但是token过长会增加请求负担,相比session安全低,一般适合单点登录
第五章 浏览器解析
1. DOCTYPE文件类型定义
- < !DOCTYPE>声明叫做文件类型定义,告诉浏览器该文件的类型,让浏览器的解析器知道用什么规范来解析文档
- < !DOCTYPE>声明必须在HTML文档的第一行,但并不是一个HTML标签
2. 解析模式
- 严格模式:标准模式,浏览器按照W3C标准解析代码
- 混杂模式:怪异模式/兼容模式,浏览器按照自己的方式解析代码,向后兼容,防止浏览器无法兼容页面
第六章 浏览器跨域
1. 同源策略
所谓同源是指:协议+域名+端⼝三者必须相同(默认端口除外),即便两个不同的域名指向同⼀个ip地址,也⾮同源,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击
2. 跨域原因
跨域的产生来源于现代浏览器所通用的同源策略限制。
当一个请求url的协议、域名、端口三者均一样的情况下,才允许访问相同的cookie、localStrage、页面dom,发送ajax请求等。
跨域请求产生时,请求已经发出且已经有响应值,只是因为浏览器同源策略的影响,响应值被拦截。
// 同源
http://www.example.com:8080/index.html
http://www.example.com:8080/home.html
// 跨域不同
http://www.example.com:8080/index.html
http://www3.example.com:8080/index.html
//同源 http默认的端口为80,https默认的端口号为443
http://www.example.com:80
http://www.example.com
https://www.example.com:443
https://www.example.com
3. 解决跨域
1)CORS
CORS支持所有类型的HTTP请求,是解决跨域http请求的根本方案
后端修改响应头:'Access-Control-Allow-Origin': '*'
2)Jsonp
前端代码:<script src='其他网站.js'></script>
jsonp是利用<script>标签没有跨域限制的漏洞
- 声明一个回调函数,用于接收数据
- 创建一个script 标签,把script的scr 赋值为跨域的api 接口地址
- 将回调函数的名字当参数挂在src上,告诉对方我的回调函数的名称,用于执行完成后来调用我的函数
优点:jsonp的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据 缺点:jsonp只支持GET请求,且容易收到xss攻击,且无任何校验
3)websocket
websocket和服务器建立了双向连接,连接建立后就可以实现双向通讯,后台利用通信发送给前端数据就不会有跨域的问题,这种方式是通过建立长链接来请求,相比普通请求会比较耗费性能。
Websocket 支持跨域,因websocket原生api用起来不太方便,推荐使用socket.io的库,并使用node.js配合前端
4)Webpack代理
一般开发环境通过proxy代理的方式解决跨域
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:3000",
pathRewrite: {"/api": ""} // 将/api替换掉
}
}
}
}
5)postMessage跨域
通过postMessage来发送跨⽂档信息,使⽤message来进⾏监听,当收到跨⽂档信息后,会触发message事件。
所有跨域的post请求,如果服务端设置了可跨域访问,都会默认发送两次请求,第一次是预检请求(options请求),查询是否支持跨域;第二次才是真正的post提交。
4. 实现单点登录
1)父域Cookie
Cookie的作用域由domain属性和path属性共同决定。domain属性的有效值为当前域或其父域的域名IP地址,在Tomcat中,domain属性默认为当前域的域名/P地址。path属性的有效值是以“/“开头的路径。在Tomcat中,path属性默认为当前Web应用的上下文路径。
如果将Cookie的domain属性设置为当前域的父域,那么就认为它是父域Cookie。Cookie有一个特点,即父域中的Cookie被子域所共享,也就是说,子域会自动继承父域中的Cookie。
利用Cookie的这个特点,可以将Session ld (或 Token)保存到父域中就可以了。我们只需要将Cookie的domain属性设置为父域的域名 (主域名),同时将 Cookie的path属性设置为根路径,这样所有的子域应用就都可以访问到这个 Cookie了。不过这要求应用系统的域名需建立在一个共同的主域名之下,如tieba.baidu.com和map.baidu.com,它们都建立在 baidu.com这个主域名之下,那么它们就可以通过这种方式来实现单点登录。
总结:此种实现方式比较简单,但不支持跨主域名