Deno使用Cache API

204 阅读3分钟

Cache API 是一种提供存储机制的接口,用于缓存 Request/Response 对象,通常用于 Service Worker 的生命周期中。它允许将请求和响应存储在浏览器的缓存中,以便稍后使用。

Cache API 是在 window 对象的作用域下暴露的,因此尽管它被定义在 service worker 的标准中,它也可以在 Service Worker 以外的脚本中使用。

一个域可以拥有多个命名的 Cache 对象,开发者可以根据需要创建和管理多个缓存。

要使用 Cache API,通常需要在脚本中处理缓存的更新逻辑,特别是在 Service Worker 中。缓存数据不会自动更新,除非明确进行缓存更新操作;缓存数据也不会自动过期,除非显式地将其删除。可以使用 CacheStorage.open(cacheName) 方法打开一个指定名称的 Cache 对象,并使用 Cache 对象的方法来处理缓存的操作,例如存储和获取请求与响应。

使用 Cache API,开发者可以轻松地将常用的请求和响应存储在缓存中,以提高网页性能和用户体验。它为开发者提供了更多灵活性和控制权,可以根据需要定制缓存的行为和策略。无论是为离线访问提供支持,还是加速资源加载,Cache API 都是一个强大而实用的工具。

当使用Cache API时,你可以执行以下几个关键操作来管理缓存:

  1. 打开或创建缓存: 使用caches.open()方法可以打开或创建一个特定名称的缓存。例如:
const cache = await caches.open('my-cache');
  1. 添加响应到缓存: 使用Cache.put()方法可以将响应添加到指定的缓存中。你需要传递一个请求对象和相应对象作为参数。例如:
const request = new Request('/api/data');
const response = new Response('{"message": "Cached response"}');
await cache.put(request, response);

与之相关的还有cache.addcache.addAll。比如add,在功能上等同于调用 fetch(),然后使用 Cache.put() 将 response 添加到 cache 中。

  1. 从缓存中获取响应: 使用Cache.match()方法可以从缓存中获取与请求匹配的响应。如果找到匹配的响应,它将作为返回值返回。例如:
const request = new Request('/api/data');
const response = await cache.match(request);
if (response) {
  // 处理响应
} else {
  // 从网络请求数据
}
  1. 删除缓存中的响应: 使用Cache.delete()方法可以从缓存中删除指定的响应。你需要传递一个请求对象作为参数。例如:
const request = new Request('/api/data');
await cache.delete(request);
  1. 清除缓存: 使用caches.delete()方法可以清除整个缓存中的所有响应。例如:
await caches.delete('my-cache');

以下是个测试页面,重点看控制台的打印:

<!DOCTYPE html>
<html>

<head>
  <title>缓存示例</title>
  <script>
    async function main() {
      const cache = await caches.open('v1');
      const jsFileUrl = './aa.js';
      try {
        const response = await cache.match(jsFileUrl);
        if (response) {
          console.info("from cache");
          console.log(await response.text());
        } else {
          const networkResponse = await fetch(jsFileUrl);
          const clonedResponse = networkResponse.clone();
          await cache.put(jsFileUrl, clonedResponse);
          const text = await networkResponse.text();
          console.info("from network", text);
        }
      } catch (error) {
        console.error("An error occurred:", error);
      }
    }
    main();
  </script>
</head>

<body>
  <!-- 页面内容 -->
</body>

</html>

访问这个HTML页面,第一次是没有缓存,但当有了缓存以后,即使你修改了aa.js的内容,也是无济于事。只能修改版本,比如caches.open('v1')改为v2。 内容在F12的缓存空间里可以找到,也能对应的删除: image.png

Deno也实现了Cache API,所以就能用它做些有意思的事情了。比如说,我们以前要完整地缓存一个接口响应,可能需要把响应的Body和Headers都存储在Map对象中,如果要持久化就更麻烦,得序列化为JSON,再存储到本地文件里。而现在只需要以下几行代码:

import { serve } from "https://deno.land/std@0.158.0/http/server.ts";

// Open a cache named v1.
const CACHE = await caches.open("v1");

serve(async (req: Request) => {
  // Requests after first request are served from cache.
  const res = await CACHE.match(req);
  if (res) {
    res.headers.set("x-cache-hit", "true");
    return res;
  }

  const { searchParams } = new URL(req.url);
  const name = searchParams.get("name");
  const response = new Response(`Hello ${name}!`);
  // Put response in cache.
  await CACHE.put(req, response.clone());
  return response;
});

这样,同一个路径的请求都被缓存下来了,即使你重启服务,也仍然生效。

$ deno run -A main.ts
Listening on http://localhost:8000/
Serving from cache http://localhost:8000/
Serving from cache http://localhost:8000/favicon.ico

正常来说,Deno的缓存应该都在DENO_DIR location里,但找了一圈也没有找到在哪儿。所以要清除这个缓存,暂时先在代码中清除吧。