从 service worker 访问 localStorage

Access localStorage from service worker

我想定期从我的 service worker 调用 API 来发送存储在 localStorage 中的数据。当用户浏览我的网站时,这些数据将产生并保存在 localStorage 中。把它想象成在 localStorage 中保存统计数据并通过 service worker 定期发送它。我应该怎么做?我知道我无法从 Service Worker 访问 localStorage,必须使用 postMessage API。任何帮助将不胜感激。

您不能从 webworker 进程访问 localStorage(以及 sessionStorage),它们的结果将是 undefined,这是出于安全原因。

您需要使用 postMessage() 返回到 Worker 的原始代码,并让该代码将数据存储在 localStorage 中。

您应该使用 localStorage.setItem()localStorage.getItem() 从本地存储中保存和获取数据。

更多信息:

Worker.postMessage()

Window.localStorage

下面的伪代码,希望它能帮助您入门:

 // include your worker
 var myWorker = new Worker('YourWorker.js'),
   data,
   changeData = function() {
     // save data to local storage
     localStorage.setItem('data', (new Date).getTime().toString());
     // get data from local storage
     data = localStorage.getItem('data');
     sendToWorker();
   },
   sendToWorker = function() {
     // send data to your worker
     myWorker.postMessage({
       data: data
     });
   };
 setInterval(changeData, 1000)

https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers

Note: localStorage works in a similar way to service worker cache, but it is synchronous, so not allowed in service workers.

Note: IndexedDB can be used inside a service worker for data storage if you require it.

这里还有一点讨论:How do I access the local storage using service workers in angular?

我一直在使用这个名为 localforage 的包,它提供了一个类似于 localStorage 的接口,环绕着 IndexedDB。 https://github.com/localForage/localForage

然后您可以通过将它放在您的 public 目录中来导入它,因此它由您的网络服务器提供服务,然后调用:self.importScripts('localforage.js'); 在您的服务工作者中。

我自己为一个小型 webapp 项目绊倒了这个问题,我考虑了以下解决方案: 当用户在线时,可以立即发送数据。当他不在线时,我使用 SyncEvent.tag 属性 从客户端向 serviceworker 发送信息。像这样:

//offline_page.html (loads only, when user is offline)

button.onclick = function() {
//on click: store new value in localStorage and prepare new value for synchronization
    localStorage.setItem("actual", numberField.value);
    navigator.serviceWorker.ready.then(function(swRegistration) {
        return swRegistration.sync.register('newval:'+numberField.value);
    });
}
//sw.js

self.addEventListener('sync', function(event) {
//let's say everything in front of ':' is the option, everything afterwards is the value
    let option = event.tag.replace(/(.*?)\:.*?$/, "");
    let value = event.tag.replace(/.*?\:(.*?)$/, "");

    if(option == "newval") {
        event.waitUntil(
            fetch("update.php?newval="+value)
            .then(function(response) {
                console.log(response);
            })
        );
    }
});

update.php 将新值保存到后端,一旦用户上线。 这不会让 service worker 访问 localStorage,但会向他发送所做的所有更改。

刚开始习惯这个同步主题。所以我真的很感兴趣,无论这是否有帮助以及其他人对此解决方案的看法。

广播频道API更容易

several ways 可以在客户端和控制 service worker 之间进行通信,但是 localStorage 不是 其中之一。 IndexedDB 是, 但这对于无论如何都应该保持苗条的 PWA 来说可能有点矫枉过正。

当然,Broadcast Channel API results the easiest. It is by far much easier to implement than above-mentioned postMessage() with the MessageChannel API

这是广播的工作原理

在 service worker 和客户端中定义一个新的广播频道。

const channel4Broadcast = new BroadcastChannel('channel4');

发送工作线程或客户端中的广播消息:

channel4Broadcast.postMessage({key: value});

在工作器或客户端中接收广播消息:

channel4Broadcast.onmessage = (event) => {
    value = event.data.key;
}