客户端存储CacheStorage

缓存数据的大小

  • 每个浏览器都硬性限制了一个域下缓存数据的大小。

  • 浏览器尽其所能去管理磁盘空间,但它有可能删除一个域下的缓存数据。

  • 浏览器要么自动删除特定域的全部缓存,要么全部保留。

StorageEstimate

  • 提供对你的域名或Web app的数据存储空间总量和已用量的估计值。

  • StorageEstimate.quota: 用户设备为你的域名或Web app预留的存储空间总大小,且该大小为估计值.虽然实际上可能有比这更多的存储空间,但这时你不应使用那多余的部分。原始的单位是byte.

  • StorageEstimate.usage: 你的域名或Web app已经使用的存储空间大小,且该大小为估计值.剩余可用空间请综合quota属性计算。原始的单位是byte。

if(navigator.storage && navigator.storage.estimate) {
  navigator.storage.estimate().then(estimate => {
    // 原始的单位是byte. 转成MB
    const ut = 1024 * 1024;
    return ({
      total: estimate.quota / ut,
      usage: estimate.usage / ut
    });
  });
};

一个域可以有多个命名 Cache 对象

  • 除非明确地更新缓存,否则缓存将不会被更新。

  • 除非删除,否则缓存数据不会过期。

CacheStorage Api

1. CacheStorage.open(cacheName)

  • params [String] cacheName
  • 接口的 open() 方法返回一个resolve为匹配 cacheName 的Cache 对象的 Promise。
  • 如果指定的 Cache 不存在,则使用该 cacheName 创建一个新的cache,并返回一个resolve为该新 Cache 对象的Promise
  // 示例
  const cacheName = 'test-cache-name'
  caches.open(cacheName).then(cache => {
    // cache 对象
    console.log('cache.....', cache);
  })

2. CacheStorage.match(request, options)

  • 检查给定的Request 对象或url字符串是否是一个已存储的 Response 对象的key. 这个方法针对 Response 返回一个 Promise ,如果没有匹配则返回 undefined 。

  • 提示: caches.match() 是一个便捷方法。其作用等同于在每个缓存上调用 cache.match() 方法 (按照caches.keys()返回的顺序) 直到返回Response 对象。

  • Request: 想要匹配的 Request。这个参数可以是 Request 对象或 URL 字符串。

  // 示例 url
  const notExistUrl = '/api'
  caches.match(notExistUrl).then(res => {
    console.log(res) // undefined
  })
  const existUrl = '/index.js'
  caches.match(existUrl).then(res => {
    console.log(res) // Response
  })
  // Request 对象
  const req = new Request('http://localhost:8008/api/ws', {
    method: 'get',
  })
  caches.match(req).then(res => {
    return res.json()
  }).then(r => {
    console.log(r); // {a: 1, b: 2}
  })
  • options: [可选] 这个对象中的属性控制在匹配操作中如何进行匹配选择。可选择参数如下:

ignoreSearch: [Boolean] 指定匹配过程是否应该忽略url中查询参数。举个例子,如果该参数设置为true, 那么 ?value=bar 作为 http://foo.com/?value=bar 中的查询参数将会在匹配过程中被忽略。该参数默认 false。

  const existUrlAndQuery = '/index.js?a=1'
  caches.match(existUrlAndQuery).then(res=>
  {
    console.log(res) // undefined
  })
  caches.match(existUrlAndQuery, {
    ignoreSearch: true
  }).then(res => {
    console.log(res) // Response
  })

ignoreMethod: [Boolean] 当被设置为 true 时,将会阻止在匹配操作中对 Request请求的 http 方式的验证 (通常只允许 GET 和 HEAD 两种请求方式)。该参数默认为 false。

// POST请求不允许缓存。

// 报错 cache.js:13 Uncaught (in promise) TypeError: Failed to execute 'add' on 'Cache': Add/AddAll only supports the GET request method.

  const req = new Request(
    'http://localhost:8008/api/ws', {
      method: 'head', // post, get, head都一样被忽略
      mode: 'cors',
    })
  caches.match(req, {
    cacheName: 'test-cache-name',
    ignoreMethod: true
  }).then(res => {
    return res.json()
  }).then(r => {
    console.log(r); // {a: 1, b: 2}
  })

ignoreVary: [Boolean] 当该字段被设置为 true, 告知在匹配操作中忽略对VARY头信息的匹配。换句话说,当请求 URL 匹配上,你将获取匹配的 Response 对象,无论请求的 VARY 头存在或者没有。该参数默认为 false。

  // 没理解
  const req = new Request('http://localhost:8008/api/ws', {
    method: 'get',
    mode: 'cors',
    vary: 'User-Agent'
  })
  caches.match(req, {
    cacheName: 'test-cache-name',
    ignoreVary: false
  }).then(res => {
    return res.json()
  }).then(r => {
    console.log(r); // {a: 1, b: 2}
  })

cacheName: [DOMString] 表示所要搜索的缓存名称.

[图片上传失败...(image-d67305-1601447981344)]
[图片上传失败...(image-28bf4e-1601447981345)]

// 指定cacheName
const cacheName = 'test-cache-name';
caches.match('/cache.js', {
  cacheName
}).then(res => {
  return res.text()
}).then(r => {
  console.log(r);
})

3. CacheStorage.has(cacheName)

  • 对象的 has()方法返回一个Promise对象,当Cache对象有cacheName时被处理为true 。
  // 存在 cacheName
  caches.has('test-cache-name').then((res) => {
    console.log(res) // true
  });
  // 不存在 cacheName
  caches.has('test-cache-name-not').then((res) => {
    console.log(res) // false
  });

4. CacheStorage.delete(cacheName)

  • delete() 方法查找匹配 cacheName的Cache对象,如果找到,则删除Cache对象并返回一个resolve为true的Promise.如果未找到Cache对象,则返回false.
  const testDeleteCacheName = 'test-delete-cache-name'
  caches.open(testDeleteCacheName).then(r => {
    // 删除test-delete-cache-name
    caches.delete(testDeleteCacheName).then((res) => {
      console.log(res); // true
    });
    // 删除不存在的test-cache-name-not
    caches.delete('test-cache-name-not').then((res) => {
      console.log(res); // false
    });
  })

5. CacheStorage.keys()

  • keys() 方法返回一个 Promise对象,它使用一个数组resolve,该数组包含 CacheStorage 对象按创建顺序跟踪的所有命名Cache对象对应的字符串。使用此方法迭代所有Cache对象。
  // 按创建顺序
  caches.keys().then(res => {
    console.log(res);
    //我本地的["my-test-cache-v1", "workbox-runtime-http://127.0.0.1:5500/", "test-cache-name"]
  })

Cache Api

  • Cache是CacheStorage某一个命名的caheName的对象,如下代码:
  // 示例
  const cacheName = 'test-cache-name'
  caches.open(cacheName).then(cache => {
    // cache对象就是cacheName为'test-cache-name'的cache对象
    console.log('cache.....', cache);
  })

1. cache.match(request, options)

  • match() 方法, 返回一个 Promise 解析为(resolve to)与 Cache 对象中的第一个匹配请求相关联的Response 。如果没有找到匹配,Promise 解析为 undefined。
  • 其他参数同CacheStorage.match()
  // 存在
  const req1 = new Request('http://localhost:8008/api/ws', {
    method: 'get',
    mode: 'cors',
  })
  const notExistUrl = 'not-exist-url'
  caches.open('test-cache-name').then(cache => {
    cache.match(req1,).then(r => {
      console.log(r); // Response
    })
    cache.match(notExistUrl,).then(r => {
      console.log(r); // undefined
    })
  })

2. cache.matchAll(request, options)

  • matchAll() 方法返回一个 Promise ,其 resolve 为 Cache 对象中所有匹配请求的数组。
  • Cache 中你尝试查找的The Request . 如果忽略这一参数,你将获取到cache中所有 response 的副本。
  cache.matchAll().then(res => {
    console.log(res) // [Response, Response, Response]
  })

3. cache.add(request)

  • add()方法接受一个URL作为参数,请求参数指定的URL,并将返回的response对象添加到给定的cache中.
  • 返回一个promise,但是res为undefined
  // cache.add方法等同于下面,默认发起一个fetch请求
  fetch(url).then(function (response) {
    if (!response.ok) {
      throw new TypeError('bad response status');
    }
    return cache.put(url, response);
  })
  const req = new Request('http://localhost:8008/v3/test-6', {
    method: 'get'
  })
  caches.open('test-cache-name').then(cache => {
    cache.add('style.css').then(res => {
      console.log('style.css....', res);
    })
    // 无需发起fetch请求,默认发起,将请求结果缓存。
    cache.add(req).then(res => {
      console.log('add....req....', res);
    })
  })

4. cache.addAll(requests)

  • addAll() 方法接受一个URL数组,检索它们,并将生成的response对象添加到给定的缓存中。 在检索期间创建的request对象成为存储的response操作的key。
  const req1 = new Request('http://localhost:8008/v3/test-1', {
    method: 'get'
  })
  const req2 = new Request('http://localhost:8008/v3/test-2', {
    method: 'get'
  })
  const req3 = new Request('http://localhost:8008/v3/test-3', {
    method: 'get'
  })
  caches.open('test-cache-name').then(cache => {
    cache.addAll([
      req1,
      req2,
      req3,
      'style.css'
    ]).then(res => {
      console.log('add....req....', res);
    })
  })

5. cache.delete(request,{options})

  • delete() 方法查询request为key的 Cache 条目,如果找到,则删除该 Cache 条目并返回resolve为true的 Promise 。 如果没有找到,则返回resolve为false的 Promise 。

  • options参数同match参数用法一致

ignoreSearch: 一个 Boolean 值,指定匹配进程中是否忽略url中的查询字符串。如果设置为true,http://foo.com/?value=bar 中的 ?value=bar 部分在执行匹配时会被忽略。默认为false。
ignoreMethod: 一个 Boolean 值,当设置为true时,将阻止匹配操作验证{domxref("Request")}} HTTP方法(通常只允许GET和HEAD)。默认为false。
ignoreVary: [Boolean] 当该字段被设置为 true, 告知在匹配操作中忽略对VARY头信息的匹配。换句话说,当请求 URL 匹配上,你将获取匹配的 Response 对象,无论请求的 VARY 头存在或者没有。该参数默认为 false。
cacheName: [DOMString] 表示所要搜索的缓存名称.

  const req1 = new Request('http://localhost:8008/v3/test-1', {
    method: 'get'
  })
  caches.open('test-cache-name').then(cache => {
    cache.delete(req1).then(res => {
      console.log(res); // true
    })
  })

6. cache.keys(request,{options})

  • keys() 方法返回一个 Promise ,这个 Promise 将解析为一个Cache 键的数组。请求将以它们被插入的顺序返回。

  • request如果一个相关键被指定,则返对应的 Request 。

  • options参数同macth用法

  const req3 = new Request('http://localhost:8008/v3/test-3', {
    method: 'get'
  })
  caches.open('test-cache-name').then(cache => {
    cache.keys().then(res => {
      console.log(res); // [Request, Request, Request]
    })
    cache.keys().then(res => {
      console.log(res); // [Request, Request, Request]
    })
    cache.keys(req3).then(res => {
      console.log('req3.....', res); // 返回对应的key req3的[Request]
    })
  })

7. cache.put(request, response)

  • put() 方法 允许将键/值对添加到当前的 Cache 对象中.
  • 注意: put() 将覆盖先前存储在匹配请求的cache中的任何键/值对。
  • 注意: Cache.add/Cache.addAll 不会缓存 Response.status 值不在200范围内的响应,而 Cache.put 允许你存储任何请求/响应对。因此,Cache.add/Cache.addAll 不能用于不透明的响应,而 Cache.put 可以。
  • 注意: 当响应主体完全写入磁盘时,初始Cache执行 (在 Blink 和 Gecko中) resolve Cache.add、Cache.addAll 和 Cache.put promise. 更新的规范版本中声明:即使响应主体仍在流式传输,一旦条目被记录到数据库中,浏览器就可以 resolve promise.
// url
const url = 'style.css';
fetch(url).then(function(response) {
  if (!response.ok) {
    throw new TypeError('Bad response status');
  }
  return cache.put(url, response);
})
// Request
const req1 = new Request('http://localhost:8008/v3/test-1', {
  method: 'get'
})
fetch(req1).then(res => {
  cache.put(req1, res)
})
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352