📜  当应用程序在Angular 8中处于脱机状态时,如何自动保存数据?(1)

📅  最后修改于: 2023-12-03 14:54:14.301000             🧑  作者: Mango

当应用程序在Angular 8中处于脱机状态时,如何自动保存数据?

在Angular 8中,我们可以通过使用Service Worker来使应用程序处于脱机状态下继续工作。Service Worker 是一种在浏览器后台运行的JavaScript线程,用于处理某些事件并缓存资源。当应用程序从服务器加载数据后,Service Worker会自动将这些数据缓存在本地,这样即使应用程序处于脱机状态,也可以从缓存中继续工作。

缓存数据
安装Service Worker

下面是如何安装Service Worker的步骤:

  1. 在Angular 8项目的根目录下新建一个文件夹:src/app/sw。可以使用以下命令:mkdir -p src/app/sw

  2. 在src/app/sw文件夹中创建一个新文件:service-worker.js。

  3. 在src/app目录中创建一个新文件:app.module.ts。

  4. 在app.module.ts文件中导入ServiceWorkerModule。代码如下:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { ServiceWorkerModule } from '@angular/service-worker';
    import { AppComponent } from './app.component';
    import { environment } from '../environments/environment';
    
    @NgModule({
      imports: [BrowserModule, ServiceWorkerModule.register('/sw/service-worker.js', { enabled: environment.production })],
      declarations: [AppComponent],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
缓存数据

下面是Service Worker如何缓存数据的步骤:

  1. 在src/app/sw/service-worker.js文件中添加以下代码:

    const CACHE_NAME = 'my-cache';
    
    self.addEventListener('install', event => {
      event.waitUntil(
        caches.open(CACHE_NAME).then(cache => {
          return cache.addAll([
            '/',
            '/index.html',
            '/styles.css',
            '/main.js'
          ]);
        })
      );
    });
    
    self.addEventListener('fetch', event => {
      event.respondWith(
        caches.match(event.request).then(response => {
          return response || fetch(event.request);
        })
      );
    });
    
  2. 在src/app/sw目录下添加一个新文件:sw-manifest.json。这个文件用于配置将要缓存的文件列表。文件内容如下:

    {
      "urls": [
        "/",
        "/index.html",
        "/styles.css",
        "/main.js"
      ]
    }
    
  3. 在app.module.ts文件中导入SwManifestWebpackPlugin并配置。代码如下:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { ServiceWorkerModule } from '@angular/service-worker';
    import { AppComponent } from './app.component';
    import { environment } from '../environments/environment';
    import { SwManifestWebpackPlugin } from 'sw-manifest-webpack-plugin';
    
    @NgModule({
      imports: [
        BrowserModule,
        ServiceWorkerModule.register('/sw/service-worker.js', { enabled: environment.production }),
        SwManifestWebpackPlugin.forRoot({ fileName: 'sw-manifest.json' })
      ],
      declarations: [AppComponent],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
自动保存数据

下面是如何使用Service Worker自动保存数据的步骤:

  1. 在AppComponent类中定义一个名为“offlineData”的属性,用于保存离线时需要保存的数据。代码如下:

    export class AppComponent {
      offlineData: any[] = [];
    }
    
  2. 在AppComponent类的构造函数中加载离线数据。代码如下:

    export class AppComponent {
      constructor() {
        const offlineDataJson = window.localStorage.getItem('offlineData');
        if (offlineDataJson) {
          this.offlineData = JSON.parse(offlineDataJson);
        }
      }
    }
    
  3. 在AppComponent类中创建一个名为“saveOfflineData”的方法,用于将数据保存到localStorage。代码如下:

    export class AppComponent {
      saveOfflineData(): void {
        window.localStorage.setItem('offlineData', JSON.stringify(this.offlineData));
      }
    }
    
  4. 在Service Worker安装完成后,从localStorage中加载离线数据。代码如下:

    const CACHE_NAME = 'my-cache';
    
    self.addEventListener('install', event => {
      event.waitUntil(
        caches.open(CACHE_NAME).then(cache => {
          return cache.addAll([
            '/',
            '/index.html',
            '/styles.css',
            '/main.js'
          ]);
        }).then(() => {
          const offlineDataJson = window.localStorage.getItem('offlineData');
          if (offlineDataJson) {
            const offlineData = JSON.parse(offlineDataJson);
            return caches.open(CACHE_NAME).then(cache => {
              return cache.put('/offline-data.json', new Response(JSON.stringify(offlineData), { status: 200, statusText: 'OK' }));
            });
          }
        })
      );
    });
    
  5. 在Service Worker中添加一个fetch事件监听器,用于在应用程序处于脱机状态下继续工作。代码如下:

    self.addEventListener('fetch', event => {
      if (event.request.method === 'GET') {
        event.respondWith(
          caches.match(event.request).then(response => {
            if (response) {
              return response;
            } else {
              return fetch(event.request);
            }
          }).catch(() => {
            return caches.match('/offline-data.json').then(response => {
              const offlineData = JSON.parse(response.body);
              const url = new URL(event.request.url);
              return new Response(offlineData.filter(item => {
                const itemUrl = new URL(item.url);
                return itemUrl.host === url.host && itemUrl.pathname === url.pathname && itemUrl.search === url.search;
              }));
            });
          })
        );
      } else if (event.request.method === 'POST' || event.request.method === 'PUT' || event.request.method === 'DELETE') {
        event.respondWith(
          fetch(event.request).then(response => {
            if (response.ok) {
              return response;
            } else {
              throw new Error();
            }
          }).catch(() => {
            event.request.clone().text().then(data => {
              const url = new URL(event.request.url);
              self.clients.matchAll().then(clients => {
                clients.forEach(client => {
                  if (url.origin === client.url) {
                    client.postMessage({ type: 'offlineData', item: { url: url.pathname + url.search, method: event.request.method, body: JSON.parse(data) } });
                  }
                });
              });
            });
            return new Response(null, { status: 202, statusText: 'Accepted', headers: { 'Content-Type': 'application/json'} });
          })
        );
      }
    });
    
  6. 在AppComponent类中添加一个名为“onMessage”的方法,用于在Web Worker中处理来自Service Worker的消息。代码如下:

    export class AppComponent {
      constructor(private ngZone: NgZone) {
        navigator.serviceWorker.addEventListener('message', event => {
          if (event.data.type === 'offlineData') {
            this.ngZone.run(() => {
              this.offlineData.push(event.data.item);
              this.saveOfflineData();
            });
          }
        });
      }
    }
    
结论

通过使用Service Worker缓存数据,Angular应用程序可以在脱机状态下继续工作,并且可以自动保存数据并在重新连接时将其保存到服务器。