澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

澳门新浦京娱乐场网站:生机勃勃篇文章通晓W

一篇文章理解Web缓存

2018/08/09 · 基础技术 · 缓存

原文出处: 这是你的玩具车吗   

最近把前端缓存重新整理了一下,从整体的层面上把前端所有能用的缓存方案梳理了一遍。同时,对于http缓存,使用了表格的方案,使得原先晦涩难记的特性变得清晰明了。特记录于此,若有什么欠缺,也望不吝指出。

时间:2017-03-27 18:02:47

参考以下文章

概述

本文主要讲述 Session Storage Cache-Control ETag Cookie 这五者的作用及区别

浏览器的缓存机制

 

HTTP文件缓存、LocalStorage、 sessionStorage、cookie、indexDB、webSQL 、CatheStorage、Application Cathe

 

1. 前端缓存概述

前端缓存主要是分为HTTP缓存和浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。下面会分别具体描述。

澳门新浦京娱乐场网站 1

该文章为 《HTML5缓存机制浅析:移动端Web加载性能优化》 的读书笔记,整理一下自己的收获。

注意,我们讨论的所有关于缓存资源的问题,都仅仅针对GET请求。而对于POST, DELETE, PUT这类行为性操作通常不做任何缓存。

Session

首先通过代码认识一下 Session。之前我们说 Cookie 可以存储我们的一些信息,但是由于用户在浏览器中可以对 Cookie 进行操作,显然这不是我们想要的,所以 Session 应运而生,Session 解决了 Cookie 不安全的痛点

HTTP文件缓存

 

1、浏览器会先查询Cathe-Control澳门新浦京娱乐场网站:生机勃勃篇文章通晓Web缓存,浏览器缓存机制。, ( cathe-control 是相对时间,expires 是绝对时间 ), 如果没有过期,则读取缓存的文件,不发送HTTP请求;

2、 浏览器检查上次有没有Etag, 如果有,就连同IF-None-Match一起发送回服务端,服务端判断Etag 有没有修改,如果没有修改,返回304,修改了返回200;

3、浏览器如果没有找到Etag ,继续找Last-Modified, 如果有,就连同 If-Modified-Since 一起向服务端发送请求,服务端判断Last-modified 是否失效,失效就返回200,没有失效就返回304;

4、如果没有找到Etag, 也没有找到 Last-Modified,直接向服务器发送请求;

澳门新浦京娱乐场网站 2

 

 

 

这么好,我们肯定要用:

前端页面:

  1. <meta http-equiv='Expires' content="Mon,20 Jul 2016 23:00:00 GMT">
  2. <meta http-equiv="Cache-Control" content="max-age=7200">   单位是毫秒,同时设定听 Cache-Control的

服务端也要配置:

const static = require('koa-static');
const app = koa();
app.use(static('/page',{
maxage = 7200;
}))

 

 

2. 前端缓存分类

一、HTML5缓存机制介绍

HTML5是新一代的HTML标准,加入很多新的特性。离线存储(也可称为缓存机制)是其中一个非常重要的特性。HTML5引入的离线存储,这意味着Web应用可进行缓存,并可在没有因特网连接时进行访问。

浏览器缓存==客户端缓存

澳门新浦京娱乐场网站 3浏览器请求静态资源的过程

下面这张图展示了某一网站,对不同资源的请求结果,其中可以看到有的资源直接从缓存中读取,有的资源跟服务器进行了再验证,有的资源重新从服务器端获取。

澳门新浦京娱乐场网站 4

浏览器缓存分为两种,分别是强制缓存协商缓存

code

我们在内存中开辟一个空间,用来存储 Session

let sessions = {}

当用户登录成功时

let sessionId = Math.random() * 1000000
sessions[ sessionId ] = { key: value }  // 表示存储的用户信息
response.setHeader( 'Set-Cookie', `sessionId = ${ sessionId }` )  // Cookie: 'sessionId = 随机数'

当此用户访问首页时,遍历 Cookie,将所有 Cookie 存储到一个 hash(哈希表)中,之后

let mySession = sessions[ hash.sessionId ]
let username
if( mySession ){
    username = mySession.用户信息  // 用户信息表示 sessions 中的{ key: value }
}

LocalStorage  

localStorage 是H5新增的方案,在各个浏览器上大小不一,ie是5m,chrome 是2.5m;

操作比较简单:setItem( ), getItem( ), removeItem( ), clear( );

多个标签页打开同一个页面的时候,localStorage 是共享的;

LocalStorage.setItem('key','value');
LocalStorage.removeItem('key');
LocalStorage.getItem('key');
LocalStorage.clear();

 

2.1 HTTP缓存

整体流程澳门新浦京娱乐场网站:生机勃勃篇文章通晓Web缓存,浏览器缓存机制。:HTTP缓存都是从第二次请求开始的。
第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,击中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否击中协商缓存,击中则返回304,否则服务器会返回新的资源。

HTTP缓存分为强缓存和协议缓存,它们的区别如下:

澳门新浦京娱乐场网站 5

200 from disk or 200 from memory :
强缓存的200也有两种情况:200 from disk和200 from memory。现在我没有找到明确的文档来描述这种区别的发生条件。知乎这个问题中提到了一些情景,可以自行取用。

1.1 HTML5应用程序缓存带来的优势

  1. 离线浏览
  2. 提高加载速度(从缓存中加载)
  3. 减少服务器负载(浏览器将只从服务器下载更新的资源,强缓存的则不发起HTTP请求,协商缓存会发起HTTP,和服务器验证文件是否修改过了)
强制缓存

浏览器在加载资源时,会根据这个资源的http请求头去看是否命中强缓存,如果命中强缓存就直接用浏览器缓存的资源,这个过程中没有发请求给服务器

Session 特点
  1. 服务器通过 Cookie(sessionId = ${ sessionId }) 将 SessionId(随机数)发给浏览器
  2. 服务器有一块内存保存了所有的 Session(哈希表)
  3. 当浏览器访问服务器时,服务器读取 SessionId
  4. 服务器通过 SessionId 可以得到对应用户的隐私信息
  5. 用户每次登录都会设置一个 SessionId,并且 SessionId 不保存在服务器中

SessionStorage

和localStorage 一样,唯一的区别就是只存在于页面清空之前,应用的不是很多

 

2.1.1 强缓存

澳门新浦京娱乐场网站 6

1.2 现有的HTML5缓存机制

勾选的,表示熟悉

  • [x] 浏览器缓存机制(强缓存,协商缓存)
  • [x] DOM Storgage 存储机制
  • [ ] Web SQL DataBase 存储机制 【关系型数据库】
  • [ ] Application Cache (App Cache)机制
  • [ ] Indexed DataBase (IndexedDB) 【NoSQL】
  • [ ] File System API

Web SQL DataBase 官方的标准文档不在推荐使用,将来也不再维护,(2015年12月);

  • 各大桌面浏览器和移动端浏览器都有很好的实现这个接口,兼容性问题不大,底层基本都是 sqlite(正因为这样,作为一个web标准是不可接受的)

    • 经测试,IOS上容量最大支持50M,不过用系统自带的safari,超过5MB,会主动提醒用户是否要增加数据库大小,不友好(不过微信里面不会)
    • 5MB 如果用来存一些日志,还是够的(当然需要记得清理旧的日志)
    • websql 目前是主要的解决方案(腾讯用来做日志记录,方便排查用户的错误反馈)
  • Indexed DataBase 是下一代的客服端结构化数据持久存储反感,目前各大浏览器中也有很好的支持,是未来用来替换 websql 的方案。

等下查下最新的情况。

这里只是官网推荐的比较,具体使用还需要看目前业界上的情况。
比如websql目前还是主流的,indexdb是未来用来替换的,具体需要多久,还需要等等。

澳门新浦京娱乐场网站 7

协商缓存

这个过程有发请求给服务器,服务器返回304,不会返回数据,还是继续用浏览器缓存的数据。

Storage

作为 Web Storage API 的接口(HTML5),Storage 提供了访问特定域名下的会话存储(session storage)和本地存储(local storage)的功能,例如:增删改查存储的数据项。Storage 与 HTTP 无关,它是浏览器上的哈希表,Storage 文件存储在本地的一个文件夹中

  • window.sessionStorage ==> 操作一个域名的会话存储(session storage)
  • window.localStorage ==> 操作一个域名的本地存储(local storage)

Cookie

一条cookie的内容包括:键,值,域,过期时间等组成;

cookie 和 webStorage 的区别:

  1. 1.大小不同。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
  2. 2.封装不同。Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
  3. 3.应用场景不同。Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生。

不同的域,cookie不能共享,否则就要跨域,跨域就要学习跨域的知识了;

但是持久性cookie可以共享浏览器;

cookie分两种,会话cookie 和 持久性cookie;若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。

 

document.cookie可以读取到cookie, 但是读取不到带有HTTPOnly 的参数的cookie,只能传输给服务器读写,这样就防止了前端的篡改,比如说:

document.cookie 的操作比webStorage麻烦的多,它是由等号和分号分隔开的字符串;

 

2.1.2 协商缓存

协商缓存都是成对出现的。
澳门新浦京娱乐场网站 8

1.3 目标

  • [ ] 分析各种缓存机制的原理,用法,特点
  • [ ] Android移动端Web性能加载优化
  • [ ] 如何利用缓存机制提高Web加载性能
与强制缓存有关的两个属性

Cache-Control和Expires

  • Cache-Control是HTTP1.1中新增的响应头
  • Expires是HTTP1.0中的响应头
  • Cache-Control使用的是相对时间
  • Expires指定的是具体的过期日期而不是秒数。因为很多服务器跟客户端存在时钟不一致的情况,所以最好还是使用Cache-Control.
  • Cache-Control和Expires同时使用的话,Cache-Control会覆盖Expires

Cache-Control有什么属性

  • max-age

指定设置缓存最大的有效时间,定义的是时间长短。当浏览器向服务器发送请求后,在max-age这段时间里浏览器就不会再向服务器发送请求了。

  • public

指定响应可以在代理缓存中被缓存,于是可以被多用户共享。如果没有明确指定private,则默认为public

  • private

响应只能在私有缓存中被缓存,不能放在代理缓存上。对一些用户信息敏感的资源,通常需要设置为private。

  • no-cache

表示必须先与服务器确认资源是否被更改过(依靠If-None-Match和Etag),然后再决定是否使用本地缓存。

  • no-store

绝对禁止缓存任何资源,也就是说每次用户请求资源时,都会向服务器发送一个请求,每次都会下载完整的资源。通常用于机密性资源。

HTTP通过缓存将服务器资源的副本保留一段时间,这段时间称为新鲜度限值。这在一段时间内请求相同资源不会再通过服务器,也就是不会向服务器发起请求。HTTP协议中Cache-Control 和 Expires可以用来设置新鲜度的限值,前者是HTTP1.1中新增的响应头,后者是HTTP1.0中的响应头。二者所做的事时都是相同的,但由于Cache-Control使用的是相对时间,而Expires可能存在客户端与服务器端时间不一样的问题,所以我们更倾向于选择Cache-Control。

当expire和cache-control都过期了,也就是过了这个新鲜度限值了,我们这个时候就要用到协商缓存了,这个时候就要跟服务器进行验证了。

  • 如果资源发生变化,则需要取得新的资源,并在缓存中替换旧资源。
  • 如果资源没有发生变化,缓存只需要获取新的响应头,和一个新的过期时间,对缓存中的资源过期时间进行更新即可。HTTP1.1推荐使用的验证方式是If-None-Match/Etag,在HTTP1.0中则使用If-Modified-Since/Last-Modified。

API

  • Storage.setItem() ==> 接收一个键名和值作为参数,把键值对添加到存储中,如果键名存在,则更新其对应的值

  • Storage.getItem() ==> 接收一个键名作为参数,返回键名对应的值

  • Storage.removeItem() ==> 接收一个键名作为参数,并把该键名从存储中删除

  • Storage.clear() ==> 清空存储中的所有键名

webSQL

最新chrome才支持;

 

2.1.3 最佳优化策略-消灭304

最佳优化策略:因为协商缓存本身也有http请求的损耗,所以最佳优化策略是要尽可能的将静态文件存储为较长的时间,多利用强缓存而不是协商缓存,即消灭304。

但是给文件设置一个很长的Cacha-Control也会带来其他的问题,最主要的问题是静态内容更新时,用户不能及时获得更新的内容。这时候就要使用hash的方法对文件进行命名,通过每次更新不同的静态文件名来消除强缓存的影响。

Hash命名:


二、分析各个缓存机制

先对各个缓存机制有一个大体的了解,然后才能去考虑如何优化。目前对 浏览器缓存和DOM Storage比较熟悉,其他的大体了解,但是没有项目中用过。

与协商缓存有关的两个属性

If-None-Match/Etag或者If-Modified-Since/Last-Modified

  • Etag是HTTP1.1推荐使用的验证方式,是指根据实体内容生成一段hash字符串,标识资源的状态,由服务端产生。浏览器会将这串字符串传回服务器,验证资源是否已经修改,如果没有修改,过程如下:

    澳门新浦京娱乐场网站 9image.png

  • ETag值通常由服务器端计算,并在响应客户端请求时将它返回给客户端

  • If-Modified-Since与Last-Modified验证过程与etag类似。这两个方式来验证时会存在下面问题:有些文档资源周期性的被重写,但实际内容没有改变。此时文件元数据中会显示文件最近的修改日期与If-Modified-Since不相同,导致不必要的响应。有些文档资源被修改了,但修改内容并不重要,不需要所有的缓存都更新最佳优化策略因为协商缓存本身也有http请求的消耗,所以最佳优化策略就是要尽可能的将静态文件存储为较长的时间,多利用强制缓存而不是协商缓存,这就是消灭304但是给文件设置一个很长的cache-control也会带来很多其他的问题,最主要的问题是静态内容个更新时,用户不能及时获得更新的内容,这个时候就需要利用hash来对文件进行命名,通过每次更新不同的静态文件名来消除强制缓存的影响。(hash值变了,就相当于要请求一个新的文件,那么肯定就跳过协商缓存和强制缓存,直接请求新的文件)

hash命名:

总结

  • 浏览器端缓存分为200 from cache和304 not modified
  • HTTP协议中Cache-Control 和 Expires可以用来设置新鲜度的限值,前者是HTTP1.1中新增的响应头,后者是HTTP1.0中的响应头。
  • max-age而Expires指定的是具体的过期日期而不是秒数
  • Cache-Control和Expires同时使用的话,Cache-Control会覆盖Expires客户端不用关心ETag值如何产生,只要服务在资源状态发生变更的情况下将ETag值发送给它就行
  • Apache默认通过FileEtag中FileEtag INode Mtime Size的配置自动生成ETag(当然也可以通过用户自定义的方式)。
  • ETag常与If-None-Match或者If-Match一起,由客户端通过HTTP头信息发送给服务端处理。
  • Last-Modified常与If-Modified-Since一起由客户端将Last-Modified值包括在HTTP头信息中发给服务端进行处理。
  • 有些文档资源周期性的被重写,但实际内容没有改变。此时文件元数据中会显示文件最近的修改日期与If-Modified-Since不相同,导致不必要的响应。

澳门新浦京娱乐场网站 10image.png

补充说明:web缓存分为两种:

  1. http缓存(从第二次请求开始的,也就是我们上面所说的强制缓存和协商缓存,都是根据response header中的一些属性来决定的。)
  2. 浏览器缓存2.1本地存储小容量Cookie主要用于用户信息的存储,Cookie的内容可以自动在请求的时候被传递给服务器。LocalStorage的数据将一直保存在浏览器内,直到用户清除浏览器缓存数据为止。SessionStorage的其他属性同LocalStorage,只不过它的生命周期同标签页的生命周期,当标签页被关闭时,SessionStorage也会被清除。2.2本地存储大缓存
  • IndexDB
  • WebSql

    澳门新浦京娱乐场网站 11image.png

    2.3 应用缓存和PWA

对象的存储
localStorage.setItem( 'object', { name: 'obj' } )  // object  [ object Object ]

澳门新浦京娱乐场网站 12

存储对象

浏览器会将 { name: 'obj' } 转化为字符串即 ({ name: 'obj' }).toString,所以当我们存储对象时,使用 JSON ,即

localStorage.setItem( 'object', JSON.stringify({ name: 'obj' }))

indexDB

进行大数据的存储,通常50m, 目前应用场景都不多,放太多东西在本地会造成数据的泄露;

 

2.2 浏览器缓存

2.1 浏览器缓存机制

浏览器缓存机制是指通过HTTP协议头里的 Cache-Control / Expires 和 Last-Modified / ETag 等字段控制文件缓存的机制。

和 DOM Storage, AppCache 等缓存机制,本质一样。 一个在HTTP协议层实现(浏览器缓存),一个在应用层实现。

localStorage

Application Cache 

通过配置manifest 文件选择性的在本地存储,

当浏览器第二次打开页面的时候,会优先从 applictionCache 来加载,然后检查  app.manifest 是否更新,如果有更新则拉取更新文件并且更新app.manifest;

<!DOCTYPE html>
<html lang="en" manifest="app.manifest">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="test.css">
</head>
<body>
<script src = 'test.js'></script>
</body>
</html>

 

/ app.manifest

  1. CHACHE MANIFEST
    #VERSION 1.0
    CHACHE
    test.css
    test.js
    
     

Application Cache 被标准弃用,浏览器不兼容, 不成熟, 被serviceWorkers 替代

 

2.2.1 本地存储小容量

Cookie主要用于用户信息的存储,Cookie的内容可以自动在请求的时候被传递给服务器。
LocalStorage的数据将一直保存在浏览器内,直到用户清除浏览器缓存数据为止。
SessionStorage的其他属性同LocalStorage,只不过它的生命周期同标签页的生命周期,当标签页被关闭时,SessionStorage也会被清除。

澳门新浦京娱乐场网站 13

2.1.1 强缓存

采用 Cache-Control 和 Expires 来控制缓存。 Chrome开发者工具NetWork, 查看为 form disk cache

澳门新浦京娱乐场网站 14

  • Cache-Control (HTTP1.1标准中新增的字段)

    1. 控制文件本地缓存的有效时间.
    2. Cache-Control:max-age=600 表示文件本地缓存有效时间600s,接下来600s内请求这个资源,浏览器不发出HTTP请求,直接从本地缓存拿
    3. 是一个相对的时间
  • Expires (HTTP1.0标准中的字段)
    1. Expires: Thu, 10 Nov 2015 08:45:11 GMT 表示在这个时间前,缓存有效
    2. 是一个绝对时间,由于服务器的时间和客服端的时间可能不一致造成缓存问题,因此引入了HTTP1.1的Cache-Control
    3. 优先级小于 Cache-Control
使用场景

记录是否提示过用户 记录一些不敏感的信息,常见新手引导界面

let already = localStorage.getItem( 'isGuide' )
if( !already ){
    // 开启引导
    localStorage.setItem( 'isGuide', true )
}

cacheStorage

用来替代Application cache的解决方案;通过window.caches 可以获取到Caches 对象,api 是下面的:

  1. window.caches.open() // 打开一个caches对象并且返回promise 对象;
  2. window.caches.has( ) //检查如果包含一个caches对象,则返回promise对象;
  3. window.caches.delete()
  4. window.caches.key()
  5. window.caches.metch()

cacheStorage 是基于serviceWorker, serviceWorker是在后台独立线程运行的js脚本,通过 message/ postmessage 方法与页面进行通信;

 

但是短期内兼容性还是很差的;

 

所以,目前可以用的只有 HTTP缓存,localStorage 和cookie了;

2.2.2 本地存储大容量

WebSql和IndexDB主要用在前端有大容量存储需求的页面上,例如,在线编辑浏览器或者网页邮箱。

澳门新浦京娱乐场网站 15

2.1.2 协商缓存

HTTP 的状态为 304 表示 协商缓存

澳门新浦京娱乐场网站 16

  • Last-Modified 和 If-Modified-Since

    Last-Modified是标识文件在服务器上的最新更新时间。下次请求时,如果文件缓存过期,浏览器通过If-Modified-Since字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果没有修改,服务器返回304告诉浏览器继续使用缓存;如果有修改,则返回200,同时返回最新的文件。

  • ETag 和 If-None-Match

    Etag也是和Last-Modified一样,对文件进行标识的字段。不同的是,Etag的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过If-None-Match字段把特征字串发送给服务器,由服务器和文件最新特征字串进行匹配,来判断文件是否有更新。没有更新回包304,有更新回包200。

Etag和Last-Modified可根据需求使用一个或两个同时使用。两个同时使用时,只要满足基中一个条件,就认为文件没有更新。

特点
  1. localStorage 与 HTTP 无关,所以 HTTP 不会带上 localStorage 的值
  2. 每个域名的 localStorage 有最大存储量,因浏览器而异
  3. 只有相同域名的页面才能互相读取 localStorage
  4. localStorage 永久有效,除非用户清除

2.2.3 应用缓存与PWA

应用缓存全称为Offline Web Application,它的缓存内容被存在浏览器的Application Cache中。它也是一个被W3C标准废弃的功能,主要是通过manifest文件来标注要被缓存的静态文件清单。但是在缓存静态文件的同时,也会默认缓存html文件。这导致页面的更新只能通过manifest文件中的版本号来决定。而且,即使我们更新了version,用户的第一次访问还是会访问到老的页面,只有下一次再访问才能访问到新的页面。所以,应用缓存只适合那种常年不变化的静态网站。如此的不方便,也是被废弃的重要原因。

PWA全称是渐进式网络应用,主要目标是实现web网站的APP式功能和展示。尽管PWA也有manifest文件,但是与应用缓存却完全不同。不同于manifest简单的将文件通过是否缓存进行分类,PWA用manifest构建了自己的APP骨架。另外,PWA用Service Worker来控制缓存的使用。这一块的内容较多,在这里就不详细展开了。

澳门新浦京娱乐场网站 17

2.1.3 F5 和 Ctrl F5 的特殊情况

手动刷新页面(F5),浏览器会直接认为缓存已经过期(可能缓存还没有过期),在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。

可能存在304协商缓存

强制刷新页面(Ctrl F5),浏览器会直接忽略本地的缓存(有缓存也会认为本地没有缓存),在请求中加上字段:Cache-Control:no-cache(或 Pragma:no-cache),发包向服务重新拉取文件。

不存在强缓存和协商缓存

sessionStorage

2.2.4 往返缓存

往返缓存又称为BFCache,是浏览器在前进后退按钮上为了提升历史页面的渲染速度的一种策略。BFCache会缓存所有的DOM结构,但是问题在于,一些页面开始时进行的上报或者请求可能会被影响。这个问题现在主要会出现在微信h5的开发中

去除BFCache有多种方法,但不是本文的重点,想了解的同学可以看《浏览器往返缓存(Back/Forward cache)问题的分析与解决》

三、LocalStorage, SessionStorage

一个简单的键值对存储系统,接口简单实用,兼容性也很好。有大小限制,提供5M(不同浏览器可能不同,区分host, cookie 只有 4k)

特点
  1. 澳门新浦京娱乐场网站,sessionStorage 与 HTTP 无关,所以 HTTP 不会带上 sessionStorage 的值
  2. 每个域名的 sessionStorage 有最大存储量,因浏览器而异
  3. SessionStorage 只在同一浏览器窗口中共享
  4. sessionStorage 在用户关闭页面后就会失效

总结

本文梳理了前端所有可能涉及的缓存,希望能从整体层面建立起系统的缓存知识体系。限于篇幅,每一部分的描述都比较简略,仅起到抛砖引玉之用。如有错误,还望指出。

1 赞 收藏 评论

澳门新浦京娱乐场网站 18

3.1 LocalStorage和 SessionStorage的用法

interface Storage { 

    readonly attribute unsigned long length;

    [IndexGetter] DOMString key(in unsigned long index); 

    [NameGetter] DOMString getItem(in DOMString key); 

    [NameSetter] void setItem(in DOMString key, in DOMString data); 

    [NameDeleter] void removeItem(in DOMString key); 

    void clear();
};

Cache-Control

Cache-Control 通用消息头被用于在 HTTP 请求和响应中通过指定指令来实现缓存机制。当我们请求的文件(css、js)很大时,可以使用 Cache-Control 实现缓存,从而达到性能优化的目的
前提:使用相同的 URL 才能实现 Cache-Control 缓存机制

HTML
<link rel = "stylesheet" href = "URL">
<script src = "URL">

3.2 LocalStorage 和 SessionStorage 的区别

LocalStorage 和 SessionStorage 的区别, SessionStorage 在页面选项卡关闭后,就不存在了, 但是 LocalStorage会还存在。但是注意:页面刷新的时候,SessionStorage还是存在的。

比如在 页面刷新后,表单填写的内容还存在,这个时候使用 SessionStorage最有用了。

后端 code

else if( path === '/js/main.js' ){
    response.setHeader( 'Cache-Control', 'max-age = 30' )  
    // 30s 内如果请求 main.js 文件,浏览器不发送请求,直接使用缓存中文件 ==> 下载时间 === 0
}

3.3 总结

分析:Dom Storage给Web提供了一种更录活的数据存储方式,存储空间更大(相对Cookies),用法也比较简单,方便存储服务器或本地的一些临时数据。

  • 适合存储简单数据
  • 如果存结构化数据,可以借住JSON的功能
  • 不适合存储复杂,存储空间要求比较大的数据,还有不适合存静态文件

特点

  1. 让浏览器在一段时间内不访问服务器,不发送请求,直接使用本地硬盘 | 内存作为响应,从而减少请求时间
  2. 首页(入口文件 HTML)不设置 Cache-Control,因为在缓存的这段时间内,用户不能获取最新网页
  3. 其他文件(css js)会缓存很久(10年,甚至更久),如要更新,只需要改变入口文件(HTML)的 URL 即可,之后浏览器就会缓存最新版的文件
  4. URL 改变实现方式: 查询参数 | 随机数
![](https://upload-images.jianshu.io/upload_images/9617841-69a7972df596f14d.png)

URL 改变实现   随机数

四、Web SQL Database存储机制

目前用来存储结构化数据还是比较主流的一个选择。 参考 《腾讯开发工程师:前端异常监控到底怎么做》&version=12020010&nettype=WIFI&fontScale=100&pass_ticket=DtgeksVBZmbExWTQ+dldANzyt56fq2HBKFKNw1N7W9hH8bytHWuxiXpvvgtPj8Au)

IOS下,最大支持50M , 系统自带浏览器Safari,默认超过5M的时候,会弹出提示让用户增加大小,不太友好。

微信浏览器下,不会提示。

Expires

Expires 头指定了一个日期 | 时间, 在这个日期 | 时间之后,HTTP响应被认为是过时的

4.1 简单例子

<script>
    if(window.openDatabase){
      //打开数据库,如果没有则创建
      var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024);
       //通过事务,创建一个表,并添加两条记录
      db.transaction(function (tx) {
           tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
           tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');
           tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');
       });
      //查询表中所有记录,并展示出来
     db.transaction(function (tx) {
         tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
             var len = results.rows.length, i;
             msg = "<p>Found rows: "   len   "</p>";
             for(i=0; i<len; i  ){
                 msg  = "<p>"   results.rows.item(i).log   "</p>";
             }
             document.querySelector('#status').innerHTML =  msg;
             }, null);
      });
}
</script>
<div id="status" name="status">Status Message</div><br>

Cache-Control | Expires

从 Expires ==> Cache-Control 是 HTTP 升级的过程,以前使用 Expires 加缓存,现在使用 Cache-Control 加缓存,Expires 的问题在于,它的过期时间是本地的时间,如果本地时间错乱,可能导致用户一直不能使用缓存,从而影响用户体验
两者的区别在于:Cache-Control 设置缓存时长,Expires 设置缓存过期时间点。如果两者同时设置,Cache-Control 优先使用

4.2 分析

  • 适合存储结构复杂的数据
  • 使用起来相对麻烦点,需要了解SQL语句
  • 不是和做静态文件的存储

ETag

ETag HTTP 响应头是资源的特定版本的标识符。可以让缓存更加高效并节省宽带,如果内容没有改变,Web 服务器不需要发送完整的响应

五、Application Cache 机制

似乎是为了支持 Web App 离线使用二开发的缓存机制。 缓存 和 浏览器缓存机制类似。

  • 按文件单位进行缓存
  • 通过manifest来控制文件的缓存
  • 大小5M的限制

AppCache的原理有两个关键点:manifest属性和 manifest文件。

  • 缓存文件有更新需要更新 manifest文件 [正常有更新文件就修改mainfest里面的一个版本号]
CACHE MANIFEST
# 2012-02-21 v1.0.0
/theme.css
/logo.gif
/main.js
NETWORK:
login.asp
FALLBACK:
/html/ /offline.html <br>

MD5

MD5 指摘要算法,它可以把一个文件转化成一个字符串。若文件内容相同,则字符串相同。文件内容差异越小,字符串(算出来的结果)差异越大

5.2 分析

分析:AppCache看起来是一种比较好的缓存方法,除了缓存静态资源文件外,也适合构建Web离线 App。在实际使用中有些需要注意的地方,有一些可以说是”坑“。

  1. 要更新缓存的文件,需要更新包含它的manifest文件,那怕只加一个空格。常用的方法,是修改manifest文件注释中的版本号。如:# 2012-02-21 v1.0.0;

  2. 被缓存的文件,浏览器是先使用,再通过检查manifest文件是否有更新来更新缓存文件。这样缓存文件可能用的不是最新的版本。

  3. 在更新缓存过程中,如果有一个文件更新失败,则整个更新会失败。

  4. manifest和引用它的HTML要在相同Host。

  5. manifest文件中的文件列表,如果是相对路径,则是相对manifest文件的相对路径。

  6. manifest也有可能更新出错,导致缓存文件更新失败。

  7. 没有缓存的资源在已经缓存的HTML中不能加载,即使有网络。例如:http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/。

  8. manifest文件本身不能被缓存,且manifest文件的更新使用的是浏览器缓存机制。所以manifest

  9. 文件的Cache-Control缓存时间不能设置太长。
    另外,根据官方文档,AppCache已经不推荐使用了,标准也不会再支持。现在主流的浏览器都是还支持AppCache的,以后就不太确定了。

后端 code

安装 MD5 npm install md5,然后 node.js 使用 MD5

else if( path === '/js/main.js' ){
    let string = fs.readFileSync( './js/main.js', 'utf-8' )
    let fileMd5 = md5( string )
    response.setHeader( 'ETag', fileMd5 )  // 响应头中有 ETag ==> ETag: md5 值
    // 当设置了 ETag 响应头,下次刷新时,请求中会多一个 If-None-Match 的请求头,值为 ETag 的值(md5 值)
    if( request.header[ 'if-none-match' ] === fileMd5 ){  // 如果请求的版本号(md5 值) === 浏览器的 If-None-Match 的值(md5 值) ==> 相同版本不需要下载
        // 没有响应体
        response.statusCode = 304  
        // 304 Not Modified 表示资源未被修改,因为请求头指定的版本If-Modified-Since或If-None-Match。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。
    } else{
        response.statusCode = 200
        // 有响应体
        response.write( string )
    }
    response.end()
}

六、 Indexed Database

IndexedDB也是一种数据库的存储机制,但不同于已经不再支持的Web SQL Database。IndexedDB不是传统的关系数据库,可归为NoSQL数据库。IndexedDB又类似于Dom Storage的key-value的存储方式,但功能更强大,且存储空间更大。

  • NoSQL数据库
  • 类似DOM Storage 键值对存储方式

缓存机制

Cache-Control ETag 联合使用

6.1 基本使用

<script type="text/javascript">
var db;
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
//浏览器是否支持IndexedDB
if (window.indexedDB) {
   //打开数据库,如果没有,则创建
   var openRequest = window.indexedDB.open("people_db", 1);
   //DB版本设置或升级时回调
   openRequest.onupgradeneeded = function(e) {
       console.log("Upgrading...");
       var thisDB = e.target.result;
       if(!thisDB.objectStoreNames.contains("people")) {
           console.log("Create Object Store: people.");
           //创建存储对象,类似于关系数据库的表
           thisDB.createObjectStore("people", { autoIncrement:true });
          //创建存储对象, 还创建索引
          //var objectStore = thisDB.createObjectStore("people",{ autoIncrement:true });
         // //first arg is name of index, second is the path (col);
        //objectStore.createIndex("name","name", {unique:false});
       //objectStore.createIndex("email","email", {unique:true});
     }
}
//DB成功打开回调
openRequest.onsuccess = function(e) {
    console.log("Success!");
    //保存全局的数据库对象,后面会用到
    db = e.target.result;
   //绑定按钮点击事件
    document.querySelector("#addButton").addEventListener("click", addPerson, false);
    document.querySelector("#getButton").addEventListener("click", getPerson, false);
    document.querySelector("#getAllButton").addEventListener("click", getPeople, false);
    document.querySelector("#getByName").addEventListener("click", getPeopleByNameIndex1, false);
}
  //DB打开失败回调
  openRequest.onerror = function(e) {
      console.log("Error");
      console.dir(e);
   }
}else{
    alert('Sorry! Your browser doesn't support the IndexedDB.');
}
//添加一条记录
function addPerson(e) {
    var name = document.querySelector("#name").value;
    var email = document.querySelector("#email").value;
    console.log("About to add " name "/" email);
    var transaction = db.transaction(["people"],"readwrite");
var store = transaction.objectStore("people");
   //Define a person
   var person = {
       name:name,
       email:email,
       created:new Date()
   }
   //Perform the add
   var request = store.add(person);
   //var request = store.put(person, 2);
   request.onerror = function(e) {
       console.log("Error",e.target.error.name);
       //some type of error handler
   }
   request.onsuccess = function(e) {
      console.log("Woot! Did it.");
   }
}
//通过KEY查询记录
function getPerson(e) {
    var key = document.querySelector("#key").value;
    if(key === "" || isNaN(key)) return;
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var request = store.get(Number(key));
    request.onsuccess = function(e) {
        var result = e.target.result;
        console.dir(result);
        if(result) {
           var s = "<p><h2>Key " key "</h2></p>";
           for(var field in result) {
               s = field "=" result[field] "<br/>";
           }
           document.querySelector("#status").innerHTML = s;
         } else {
            document.querySelector("#status").innerHTML = "<h2>No match!</h2>";
         }
     }
}
//获取所有记录
function getPeople(e) {
    var s = "";
     db.transaction(["people"], "readonly").objectStore("people").openCursor().onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            s  = "<p><h2>Key " cursor.key "</h2></p>";
            for(var field in cursor.value) {
                s = field "=" cursor.value[field] "<br/>";
            }
            s ="</p>";
            cursor.continue();
         }
         document.querySelector("#status2").innerHTML = s;
     }
}
//通过索引查询记录
function getPeopleByNameIndex(e)
{
    var name = document.querySelector("#name1").value;
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var index = store.index("name");
    //name is some value
    var request = index.get(name);
    request.onsuccess = function(e) {
       var result = e.target.result;
       if(result) {
           var s = "<p><h2>Name " name "</h2><p>";
           for(var field in result) {
               s = field "=" result[field] "<br/>";
           }
           s ="</p>";
    } else {
        document.querySelector("#status3").innerHTML = "<h2>No match!</h2>";
     }
   }
}
//通过索引查询记录
function getPeopleByNameIndex1(e)
{
    var s = "";
    var name = document.querySelector("#name1").value;
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var index = store.index("name");
    //name is some value
    index.openCursor().onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            s  = "<p><h2>Key " cursor.key "</h2></p>";
            for(var field in cursor.value) {
                s = field "=" cursor.value[field] "<br/>";
            }
            s ="</p>";
            cursor.continue();
         }
         document.querySelector("#status3").innerHTML = s;
     }
}
</script>
<p>添加数据<br/>
<input type="text" id="name" placeholder="Name"><br/>
<input type="email" id="email" placeholder="Email"><br/>
<button id="addButton">Add Data</button>
</p>
<p>根据Key查询数据<br/>
<input type="text" id="key" placeholder="Key"><br/>
<button id="getButton">Get Data</button>
</p>
<div id="status" name="status"></div>
<p>获取所有数据<br/>
<button id="getAllButton">Get EveryOne</button>
</p>
<div id="status2" name="status2"></div>
<p>根据索引:Name查询数据<br/>
    <input type="text" id="name1" placeholder="Name"><br/>
    <button id="getByName">Get ByName</button>
</p>
<div id="status3" name="status3"></div><br>

辨析

6.2 分析

分析:IndexedDB是一种灵活且功能强大的数据存储机制,它集合了Dom Storage和Web SQL Database的优点,用于存储大块或复杂结构的数据,提供更大的存储空间,使用起来也比较简单。可以作为Web SQL Database的替代。不太适合静态文件的缓存。

  1. 以key-value 的方式存取对象,可以是任何类型值或对象,包括二进制。

  2. 可以对对象任何属性生成索引,方便查询。

  3. 较大的存储空间,默认推荐250MB(分Host),比Dom Storage的5MB要大得多。

  4. 通过数据库的事务(tranction)机制进行数据操作,保证数据一致性。

  5. 异步的 API 调用,避免造成等待而影响体验。

Cookie Session

  1. Cookie 指某些服务器在浏览器终端的一些数据(通常经过加密),一般为了辨别用户身份,也可以储存少量信息
  2. Session 是指服务器通过某种方式确定了用户身份后的会话状态,一般表现为服务器为每个用户单独存储的一部分数据
  3. Session 是基于 Cookie 实现的,Cookie 是 Session 的基石
  4. Cookie 存储在浏览器本地,用户可以看到内容。Session 存储在服务器,用户无法查看内容,一般 Session 的内容是进程线程间共享的
  5. Cookie 不安全,而 Session 解决了 Cookie 不安全的痛点

七、File System API

  • HTML5新加入的存储机制
  • 为 webApp提供了虚拟的文件系统,类似Native App访问本地系统一样

Cookie Storage

  1. Cookie 和 Storage 都存储在本地的一个文件中
  2. 两者都可以做跨页面通信,两者都不能跨域访问
  3. Cookie 的每次请求相同域名时,都会带上 Cookie 里的所有内容去访问服务器
  4. Storage 与 HTTP 无关,不会被带给服务器
  5. Cookie 在做跨页面通信时,由于带上所有内容,导致上传数据 请求变慢,Storage 的出现解决了 Cookie 的痛点,只要将一些不敏感信息存储在 Storage 中即可
  6. JS 调用 Cookie 比较麻烦,一般都用库进行封装。Storage 调用起来比较简单,也可以再次封装达到更好的效果
  7. Cookie 大小 4K 左右,Storage 大小 5M 左右
  8. 后台代码可以任意设置 Cookie 的过期时间。Storage 中的 LocalStorage 永久有效,除非用户删除,Storage 中的 SessionStorage 在用户关闭页面(Session 结束)后就失效

7.1 File System 的优势

  • 满足大块的二进制文件存储
  • 通过预加载资源文件提供性能
  • 可以直接编辑文件

LocalStorage SessionStorage

  1. 两者与 HTTP 无关
  2. 每个域名的 LocalStorage | sessionStorage 有最大存储量,因浏览器而异
  3. 只有相同域名的页面才能互相读取 LocalStorage。SessionStorage 只在同一浏览器窗口中共享
  4. LocalStorage 本地存储, SessionStorage 会话存储
  5. LocalStorage 永久有效,除非用户删除。SessionStorage 在用户关闭页面(Session 结束)后就失效

7.2 两种文件空间

  • 临时型

由浏览器自动分配的,但可能被浏览器收回

  • 持久性

需要显示的申请,申请时浏览器会给用户提示,让用户确定。浏览器不会收回(提供用户则不太友好),大小不够用需要再次申请。

Cache-Control ETag

  1. 两者都是 HTTP 响应头,都可以实现加快请求 | 响应速度
  2. Cache-Control 是直接使用本地缓存,不会发送请求
  3. ETag 发送请求,如果 MD5 值相同,则没有响应体

7.3 分析

File System API给Web App带来了文件系统的功能,Native文件系统的功能在Web App中都有相应的实现。任何需要通过文件来管理数据,或通过文件系统进行数据管理的场景都比较适合。

八、参考文章

  1. 《HTML5缓存机制浅析:移动端Web加载性能优化》
  2. 《腾讯开发工程师:前端异常监控到底怎么做》&version=12020010&nettype=WIFI&fontScale=100&pass_ticket=DtgeksVBZmbExWTQ+dldANzyt56fq2HBKFKNw1N7W9hH8bytHWuxiXpvvgtPj8Au)

本文由澳门新浦京娱乐场网站发布于新浦京娱乐场官网,转载请注明出处:澳门新浦京娱乐场网站:生机勃勃篇文章通晓W