Service Worker 很棒。它们使 Web 开发人员可以实现以前原生应用专有的类似功能。这类功能是例如推送通知或后台同步的离线功能。
它们是渐进式 Web 应用的核心。但是在设置它们之后,似乎很难完成涉及与 Web 应用交互的更复杂的事情。
在本文中,我将展示可用的选择并最后进行比较。
如果你查看 Service Workers 的 api,将会看到 Web Worker 和 Service Worker 有非常相似的接口。尽管有相似之处,但它们的意图和功能却大不相同:
它们可以在多个标签中使用,甚至在所有标签关闭后仍然可以使用。
它们仅限于一个标签 。
两者的共同点是它们无权访问 dom,无法使用 postMessage API 进行通信。你可以将它们看作是具有扩展功能的 Web Worker。
如果你想了解有关它们更多信息,请查看这个对话,尽管有些陈旧,但可以个很好的概述这个话题。到 2020 年,Service Workers 的浏览器支持有了很大的改进。
对于任何来源,都可以有多个 Service Worker。以下内容返回当前控制页面的活动 Service Worker:
navigator.serviceWorker.controller
如果要访问其他 Service Worker,则可以通过 registration 接口访问,该借口使你可以访问以下位置的 Service Worker 状态:
你可以通过几种不同的方式访问 registration 接口。其中有一个 navigator.serviceWorker.ready。它将返回一个可以通过注册解决的 promise:
navigator.serviceWorker.ready.then((registration) => {
// At this point, a Service Worker is controlling the current page
});
如果你想了解有关 Service Worker 生命周期的更多信息,请查看这篇文章:(https://bitsofco.de/the-servi...)。
正如我已经提到的,Service Worker 通过 postMessage API 进行通信。这不仅允许他们与JavaScript主线程交换数据,而且还可以将消息从一个Service Worker发送到另一个Service Worker。
// app.js - Somewhere in your web app
navigator.serviceWorker.controller.postMessage({
type: 'MESSAGE_IDENTIFIER',
});
// service-worker.js
// On the Service Worker side we have to listen to the message event
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MESSAGE_IDENTIFIER') {
// do something
}
});
这种单向通信的用例是在等待服务的 Service Worker 中调用 skipWaiting,然后将其传递为活动状态并控制页面。这已在 Create-react-App 附带的 Service Worker 中实现。我用此技术在渐进式 Web 应用中显示更新通知,我在这篇文章(https://felixgerschau.com/cre...)中进行了解释。
但是如果你想将消息发送回 Window上下文甚至其他 Service Worker,该怎么办?
有好几种方法可以将消息发送到 Service Worker 的客户端:
我将为你提供每个方法的简短示例,然后将它们进行比较,以查看哪种方法最适合你的用例。
我没有包含 FetchEvent.respondWith(),因为这仅适用于获取事件,而且目前不受 Safari 浏览器支持。
顾名思义,MessageChannel API 设置了一个可以发送消息的通道。
该实现可以归结为3个步骤。
也可以添加第四步,如果你想通过在 Service Worker 中调用 port.close() 来关闭连接的话。
在实践中看起来像这样:
// app.js - somewhere in our main app
const messageChannel = new MessageChannel();
// First we initialize the channel by sending
// the port to the Service Worker (this also
// transfers the ownership of the port)
navigator.serviceWorker.controller.postMessage({
type: 'INIT_PORT',
}, [messageChannel.port2]);
// Listen to the response
messageChannel.port1.onmessage = (event) => {
// Print the result
console.log(event.data.payload);
};
// Then we send our first message
navigator.serviceWorker.controller.postMessage({
type: 'INCREASE_COUNT',
});
// service-worker.js
let getVersionPort;
let count = 0;
self.addEventListener("message", event => {
if (event.data && event.data.type === 'INIT_PORT') {
getVersionPort = event.ports[0];
}
if (event.data && event.data.type === 'INCREASE_COUNT') {
getVersionPort.postMessage({ payload: ++count });
}
}
Broadcast API 与 MessageChannel 非常相似,但是它消除了将端口传递给 Service Worker 的需求。
在这个例子中,我们看到只需要在两侧建立一个有相同名称 count-channel 的通道。
我们可以将相同的代码添加到其他 WebWorker 或 Service Worker,后者也将接收所有这些消息。
在这里,我们从上方看到了相同的例子,但用了 Broadcast API:
// app.js
// Set up channel
const broadcast = new BroadcastChannel('count-channel');
// Listen to the response
broadcast.onmessage = (event) => {
console.log(event.data.payload);
};
// Send first request
broadcast.postMessage({
type: 'INCREASE_COUNT',
});
// service-worker.js
// Set up channel with same name as in app.js
const broadcast = new BroadcastChannel('count-channel');
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'INCREASE_COUNT') {
broadcast.postMessage({ payload: ++count });
}
};
Client API 也不需要传递对通道的引用。
在客户端,我们侦听 Service Worker 的响应,在 Service Worker 中,用 self.clients.matchAll 函数提供给我们的过滤器选项,选择要发送响应的客户端。
// app.js
// Listen to the response
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'REPLY_COUNT_CLIENTS') {
setCount(event.data.count);
}
};
// Send first request
navigator.serviceWorker.controller.postMessage({
type: 'INCREASE_COUNT_CLIENTS',
});
// service-worker.js
// Listen to the request
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'INCREASE_COUNT') {
// Select who we want to respond to
self.clients.matchAll({
includeUncontrolled: true,
type: 'window',
}).then((clients) => {
if (clients && clients.length) {
// Send a response - the clients
// array is ordered by last focused
clients[0].postMessage({
type: 'REPLY_COUNT',
count: ++count,
});
}
});
}
});
postMessage API提供了一个简单灵活的接口,使我们可以将消息发送给 Service Worker。
Broadcast Channel API 是最容易使用的选项,但不幸的是,它的浏览器支持并不是很好。
在剩下的两个中,我更喜欢 Client API,因为这不需要将引用传递给 Service Worker。
作者:Felix Gerschau
翻译:疯狂的技术宅
原文:https://felixgerschau.com/
每个 Vue 实例都实现了事件接口vm.$emit( event, arg ) 触发当前实例上的事件;vm.$on( event, fn )监听event事件后运行。实例说明:Vuejs 用$emit与$on来进行兄弟组件之间的数据传输通信,Vuejs 用$emit与$on来进行跨页面之间的数据传输通信
两个浏览器窗口间通信:一个窗口更新localStorage,另一个窗口监听window对象的storage事件来实现通信;所有的WebSocket都监听同一个服务器地址,利用send发送消息,利用onmessage获取消息的变化;借助iframe 或 window.open;HTML5 中的 Web Worker 可以分为两种不同线程类型
在浏览器中,我们可以同时打开多个Tab页,每个Tab页可以粗略理解为一个“独立”的运行环境,即使是全局对象也不会在多个Tab间共享。然而有些时候,我们希望能在这些“独立”的Tab页面之间同步页面的数据、信息或状态。
使用Vue也有很长一段时间,但是一直以来都没对其组件之间的通信做一个总结,这次就借此总结一下。父子组件之间的通信props和$emit 父组件通过props将数据下发给props
前端开发过程中,总是避免不了要进行前端标签页之间的通信,最经典的例子莫过于音乐播放网站中,当第一次点击播放列表中的歌曲时,它会打开一个新的标签页进行播放,而当在列表中再次点击歌曲播放时
我们的项目是基于 ThinkJS + Vue 开发的,最近实现了一个多端实时同步数据的功能,所以想写一篇文章来介绍下如何在 ThinkJS 的项目中利用 WebSocket 实现多端的实时通信。ThinkJS 是基于 Koa 2 开发的企业级 Node.js 服务端框架
其实服务器的处理和客户端大同小异,分三个逻辑分支:检索成功,用检索到的Socket来处理接收报文;检索失败,服务器侦听(listen)目的端口,创建全新的Socket服务客户;检索失败,服务器没有侦听目的端口,丢弃处理
如何实现两个组件之间的双向传递呢?即,在父组件中修改了值,子组件会立即更新。在子组件中修改了值,父组件中立即更新。vue中有一个很神奇的东西叫v-model,它可以完成我们的需求。
vue项目的一大亮点就是组件化。使用组件可以极大地提高项目中代码的复用率,减少代码量。但是使用组件最大的难点就是父子组件之间的通信。父组件通过$refs调用子组件的方法。 以上就是父子组件通信的方式
在微服务架构的世界中,我们通过一系列服务构建应用。集合中的每项服务都符合以下标准:松散耦合、可维护和可测试、可以独立部署,微服务架构中的每个服务都解决了应用中的业务问题
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!