PWA 中的在线和离线资源 - 使用 Django 开发渐进式 Web 应用程序

注:首次发布于:https://andresalvareziglesias.substack.com/p/pwa-and-django-3-online-and-offline

欢迎阅读 Django 渐进式 Web 应用程序系列的第三篇。在本章中,我们将学习如何缓存 PWA 的资源,以便能够在没有活动互联网连接的情况下离线使用它们。

Online and offline resources in a PWA - Developing Progressive Web Applications with Django

实现离线功能

在前面的章节中,我们定义了一个小型 PWA 应用程序,其中包含所有必需部分:清单和 ServiceWorker。我们学习了如何注册 PWA,并使用一些图像开发了一个非常简单的界面:

A very simple interface with some images for our demo PWA

现在我们将学习如何将数据存储在 PWA 缓存中,以及如何选择从哪里加载每个图像:从互联网还是从本地缓存。

为了将一个或多个资源存储在 PWA 缓存中,我们在 ServiceWorker 上使用如下函数:

const CACHE_NAME = "DJANGO_PWA_TEST"
const MAIN_URL = "https://laboratorio.alvarezperello.com/djangopwa/";

self.addEventListener("install", (event) => {
   console.info("*** PWA event *** install", event);
   event.waitUntil(activateApp());
});

self.addEventListener("activate", (event) => {
   console.info("*** PWA event *** activate", event);
   event.waitUntil(activateApp());
});

async function activateApp() {
   // When a service worker is initially registered, pages won't use it
   // until they next load. The claim() method causes those pages to be
   // controlled immediately.
   console.log('Claiming control...');
   clients.claim().then((ev) => {
       console.log('...claimed!', ev);
   })

   manageCache();
}

self.addEventListener("sync", (event) => {
   console.info("*** PWA event *** sync", event);
   manageCache();
});

async function manageCache() {
   const cache = await caches.open(CACHE_NAME);
   if (!cache) {
       console.error("Error storing resources in cache!");
       return;
   }

   storeResourceInCache(cache, MAIN_URL+"static/demo/img/snake1.jpg");
   //storeResourceInCache(cache, MAIN_URL+"static/demo/img/snake2.png");
   //storeResourceInCache(cache, MAIN_URL+"static/demo/img/snake3.png");
}

async function storeResourceInCache(cache, element) {
   console.log("Storing resource in cache: "+element);
   cache.add(element).then(event => {
       console.info("Resource stored successfully! "+element);
   }).catch(event => {
       console.error("Error storing resource! "+element, event);
   });
}

现在,当我们执行 PWA 时,我们可以在开发者控制台中读取缓存消息:

Registering service worker...
...register completed!
The service worker is active!

serviceworker.js: Claiming control...
serviceworker.js: Resource already in cache! static/demo/img/snake1.jpg

我们的 PWA 缓存正在运行!

选择从哪里加载每个资源

当 PWA 加载资源时,调用 fetch 事件,如下所示:

self.addEventListener("fetch", async (event) => {
   console.info("*** PWA event *** fetch", event);

   let url = event.request.url.toString();
   console.info("The PWA is loading a resource from: "+url);
});

我们现在可以控制请求,并可以选择从哪里返回请求的资源:从缓存或从互联网。

下面是一个示例,说明如何检查是否有缓存的资源并从缓存中返回。如果没有缓存,则从互联网请求。

self.addEventListener("fetch", async (event) => {
   let url = event.request.url.toString();
   if (!url.includes("static/demo/img/snake")) {
       return false;
   }

   const cache = await caches.open(CACHE_NAME);
   if (!cache) {
       console.error("Error loading resources from cache!");
       return false;
   }

   let fetchResponsePromise = await cache.match(url).then(async (cachedResponse) => {
       if (cachedResponse && cachedResponse.ok) {
           console.warn("Loading from cache: "+url);
           return cachedResponse;

       } else {
           console.error("Error! the cache does not have this url! "+url);
           console.error(cache.keys());

           remoteFetchResponsePromise = await fetch(event).then(async (networkResponse) => {
               console.warn("Loading from internet: "+url);
               return networkResponse;
           });

           return remoteFetchResponsePromise;
       }
   });

   return (await fetchResponsePromise);
});

我们可以读取开发者控制台来了解每个图像的加载位置,如下所示:

From where our PWA loads every image: cache or internet

在下一章中

我们现在有一个 PWA。现在我们将学习如何制作可安装的 PWA,它将在操作系统中显示为本机应用程序。这是 PWA 最棒的功能之一:我们可以用它们使用 Django 创建“几乎本机”的应用程序。

下一章再见!

关于该名单

在 Python 和 Docker 文章中,我还将撰写其他相关主题,例如:

  • 软件架构
  • 编程环境
  • Linux 操作系统
  • ETC。