从 service worker 访问 localStorage
Posted
技术标签:
【中文标题】从 service worker 访问 localStorage【英文标题】:Access localStorage from service worker 【发布时间】:2017-04-14 17:35:46 【问题描述】:我想定期从我的 Service Worker 调用 API 以发送存储在 localStorage
中的数据。当用户浏览我的网站时,这些数据将被生成并保存在localStorage
。将其视为将统计信息保存在localStorage
并通过服务人员定期发送。我该怎么做?我知道我无法从服务人员访问localStorage
,必须使用postMessage
API。任何帮助将不胜感激。
【问题讨论】:
即使这个问题提到了角度,它也包含一个可能的答案:***.com/questions/52721826/… @Faiz 你找到解决办法了吗? 【参考方案1】:广播频道 API 更简单
有several ways 用于客户端和控制服务工作者之间的通信,但localStorage
不是其中之一。
IndexedDB
是, 但这对于无论如何都应该保持苗条的 PWA 来说可能有点过头了。
无论如何,Broadcast Channel API 结果最简单。它比上面提到的postMessage()
和MessageChannel API 更容易实现。
这是广播的工作原理
在服务工作者和客户端中定义一个新的广播频道。
const channel4Broadcast = new BroadcastChannel('channel4');
要在工作人员或客户端中发送广播消息:
channel4Broadcast.postMessage(key: value);
要在工作人员或客户端中接收广播消息:
channel4Broadcast.onmessage = (event) =>
value = event.data.key;
【讨论】:
非常干净。直截了当,没有太多花里胡哨和解决方法 最好的方法【参考方案2】:我自己为一个小型 webapp 项目偶然发现了这个问题,我考虑了以下解决方案:
当用户在线时,可以立即发送数据。当他离线时,我使用SyncEvent.tag
属性将信息从客户端发送到服务人员。像这样:
//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(/(.*?)\:.*?$/, "$1");
let value = event.tag.replace(/.*?\:(.*?)$/, "$1");
if(option == "newval")
event.waitUntil(
fetch("update.php?newval="+value)
.then(function(response)
console.log(response);
)
);
);
update.php
将新值保存到后端,一旦用户上线。
这不会让 Service Worker 访问 localStorage,但会向他发送所做的所有更改。
刚刚开始习惯这个同步主题。所以我真的很感兴趣,无论这是否有帮助以及其他人对此解决方案的看法。
【讨论】:
IMO - 同步并不总是可用(浏览器支持并且用户可以禁用它),此外这看起来过于复杂 - 为什么不简单地发送消息? navigator.serviceWorker.controller.postMessage( value:'...' , [new MessageChannel().port2]);【参考方案3】:我一直在使用这个名为 localforage
的包,它提供了一个类似于 localStorage 的接口,它围绕着 IndexedDB。 https://github.com/localForage/localForage
然后,您可以通过将其放置在您的公共目录中来导入它,以便由您的网络服务器提供服务,然后在您的服务人员中调用:self.importScripts('localforage.js');
。
【讨论】:
IndexedDB 在 Service Worker 中工作——这就是 LocalForage 工作的原因(它默认为 IndexedDB)。这个问题是关于 LocalStorage 的,Service Workers 无法访问它 @Robert Question 说“我知道我无法访问 localStorage...任何帮助将不胜感激。” 尽管此答案不包括使用 localStorage 的解决方案,但它提供了一个极好的替代方案,易于实现并保持用户熟悉的类似语法。我已经尝试过这个解决方案,它是一个非常容易实现和从本地存储迁移的方法。【参考方案4】:您不能从 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)
【讨论】:
var myWorker = new YourWorker('YourWorker.js'),
> new WebWorker
对吧?
@Roberrrt 感谢您的评论,正确的是new Worker()
:)
感谢 GibboK,但我有几个疑问。您提到的代码将在我的一个 javascript 中运行。为了运行这个用户必须让网站运行?不是吗?我正在寻找服务工作者定期从本地存储发送数据的东西,即使用户不在我的网站上也是如此。我的情况甚至可能吗?
@Faiz 如果您认为我的回答对您有所帮助,请不要忘记点击左侧 V 图标接受它。感谢和愉快的编码:)
@FelipeMorales afik 它应该也适用于服务工作者与网页的通信必须通过服务工作者 PostMessage 方法。但请试一试,让我们知道:)【参考方案5】:
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers 说
注意:localStorage 的工作方式与 Service Worker 缓存类似,但它是同步的,因此不允许在 Service Worker 中使用。
注意:如果需要,可以在 Service Worker 内部使用 IndexedDB 进行数据存储。
这里也有一点讨论:How do I access the local storage using service workers in angular?
【讨论】:
以上是关于从 service worker 访问 localStorage的主要内容,如果未能解决你的问题,请参考以下文章