6:26 you also run into maximum connections per origin limits when using EventSource over HTTP/1.1, so if you have >6 tabs open then at least one won't be able to create an EventSource. (This is mostly fixed with HTTP/2+) see stackoverflow.com/questions/16852690/sseeventsource-why-no-more-than-6-connections
With my user hat on - please don't over-use this kind of thing. Sometimes I will open another tab precisely because I want one to stay in its current state, for later reference. The examples mentioned in the video sound fine to me, but taking this kind of technique to the extreme could just be annoying to the user.
Service worker's are fiddly and service worker messaging is even more fiddly. As for the observers discussed at the end, that's a really nice pattern, I like to use that with a Websocket to a server that stores the state, but it would of course be nice if it didn't require a server.I didn't know about the localStorage listener, thanks!
There is a feature request bug for BroadcastChannel in Safari: bugs.webkit.org/show_bug.cgi?id=161472. It’s currently blocked by a spec issue around partitioning: github.com/whatwg/html/issues/5803.
I can't find any mention on the web that Safari on IOS supports the client API . Does clients.MatchAll work with it? see at 12:06 - so why does this method score 1.000
@@jakearchibald I spent yesterday building a service worker and then seeing if it would work on a Macbook Air and an iPad and it appears to work fine (other CSS problems but ...). The way I retrieve this data is by actually adding to my "api" name space a "service" section where the service worker responds and never passes the request to my server. ``` const api = /^\/api\/(service|config|session|profile|approve|gadm)\/(\w+)|(\d+)\/(admin|user)\/(\w+)$/i; self.addEventListener('fetch', (event) => { const requestURL = new URL(event.request.url); if (/^\/api\//i.test(requestURL.pathname)) { //We have an api call, so deal with it appropriately const matches = api.exec(requestURL.pathname); if (matches === null) { //let the browser do its own thing } else { switch (matches[1]) { case 'service': //service worker request , lets do it switch(matches[2]) { case 'tab': event.respondWith( self.clients.matchAll({includeUncontrolled: true}).then(clients => new Response(clients.length.toString(),{status: 200, headers: { 'Cache-Control': 'no-cache', 'Content-Type': 'text/plain; charset=US-ASCII', } }))); break; default: event.respondWith(new Response('', { status: 404 }));//unknown so send a 404 } break; case 'config': ... ```
@@riddixdan5572 compared to structured cloning, JSON cannot store: circular references, BigInt, Date, RegExp, ArrayBuffer, any of the ArrayBufferViews, Map, Set, Error, ImageData, ImageBitmap, Blob, File… there are probably more I'm forgetting.
@@jakearchibald Hmh, fair enough, but there are always libraries that can imitate it somewhat. but yeah, probably not everything, I guess circular reference would be the easiest to imitate. Can't say the same for other examples you brought tho.
@@riddixdan5572 Oh yeah you can make your own serialisation format if you must. But why not use one of the other storage systems that does all that for you?
You mention that storage event is triggered when session storage is changed, but I believe session storage is not shared between different windows and the event does NOT trigger
if you want to sync tabs across sub domains, you will have to create a JavaScript cookie and do pooling on it. YIKES IK. I don’t know any other way other than going server side.
Hi, thanks for this video! We solved the task of synchronizing tabs through service worker, but we came across the fact that sw periodically falls asleep and does not respond to messages from its customers. Please tell me how to proceed in this case and is the estimate of 1.000 correct? We started using shared workers for synchronization, and it has proven itself perfectly
Sending the service worker a message via fetch or postMessage should always wake it up. If you've found a case where it doesn't, it's a bug. However, if you're expecting the service worker to stay awake when it isn't doing anything… that isn't what it's designed for.
@@jakearchibald No, we do not expect and do not want the worker service to always be in an active state, however, we hoped that the postMessage message from the tab (his client) would wake him up. Moreover, this behavior is very difficult to catch. Anyway, we switched to shared workers, please tell me how much better this solution is. Or is it better to deal with the service worker after all? I like the service worker because it keeps the list of clients always up to date. In turn, in the shared worker, you need to monitor the customers yourself
Only a very specific subset of objects. You can have cyclic structures in JavaScript, but that doesn't translate to JSON. JSON can't handle Maps, Sets, ArrayBuffer/ArrayBufferViews, classes, prototypes... lots of things can get lost when stringifying.
Surma Exactly, and this should be enough for most use cases. Needing to store abstract objects on the client side is a pretty rare scenario. And in some cases you can prepare complex object(s) before the "stringification". But I get your point!
Emrah ATILKAN Well it is still a JSON String though but technically not an object anymore, that’s true. Nevertheless you are still able to store objects, just not directly as objects while being in the storage. Got me there.
Well, postMessage should summarize it. And it's mentioned in BroadcastChannel. BroadcastChannel should have a better score nowadays, given its support.
4:11 | window.postMessage (needs window reference of another window, e.g. via window.open) | Score: 0.248
5:57 | EventSource (HTTP event stream, cross-device) | Score: 0.492
8:30 | window's localstorage change event (no message to current window) | Score: 0.763
10:33 | Broadcast channel (channel->other same name channels; no safari support) | Score: 0.635
11:39 | Service worker (window->worker->all windows) | Score: 1
13:06 | IndexedDB Observers (experimental) | Score: 0.005
13:37 Butterflies in my chest-- genuine feeling of joy
13:41 Oh, maybe some little issue
13:42 Crushing sadness and feeling betrayed
Yep, the sum is correct.
phew
came down to the comments just to check lol. At least they didn't have a typo like they did in the Squoosh.app episode.
6:26 you also run into maximum connections per origin limits when using EventSource over HTTP/1.1, so if you have >6 tabs open then at least one won't be able to create an EventSource. (This is mostly fixed with HTTP/2+)
see stackoverflow.com/questions/16852690/sseeventsource-why-no-more-than-6-connections
With my user hat on - please don't over-use this kind of thing. Sometimes I will open another tab precisely because I want one to stay in its current state, for later reference. The examples mentioned in the video sound fine to me, but taking this kind of technique to the extreme could just be annoying to the user.
The existence of such technology does not really mean that it should be integrated on each site on the web
the math checks out:
0.248+0.492+0.763+0.635+1+0.005 = 3.143
my reputation is safe
Yeah but can someone check if this guy's check cheks out?
Waiting for observers to be implemented in Indexed DB!! Also there is an Observable in DixieJs(an idb wrapper) if anyone is interested.
Jake you chose a very interesting topic to discuss. I appreciate it :)
That was really interesting. Perhaps, the best among 2020 videos
Thanks for the scientifically-proven and methodological scores ❤️
Service worker's are fiddly and service worker messaging is even more fiddly. As for the observers discussed at the end, that's a really nice pattern, I like to use that with a Websocket to a server that stores the state, but it would of course be nice if it didn't require a server.I didn't know about the localStorage listener, thanks!
gone not forgotten 6:18 ❤❤❤
What happened to him?
Great show!
any updates on IDBObserver? Not finding much on it and wondering if it is stalled ...
There is a feature request bug for BroadcastChannel in Safari: bugs.webkit.org/show_bug.cgi?id=161472. It’s currently blocked by a spec issue around partitioning: github.com/whatwg/html/issues/5803.
It works on Safari now (since march 2022)
I can't find any mention on the web that Safari on IOS supports the client API . Does clients.MatchAll work with it? see at 12:06 - so why does this method score 1.000
I'm pretty sure it does
I mean, if it doesn't, then I've messed up my scoring
@@jakearchibald I spent yesterday building a service worker and then seeing if it would work on a Macbook Air and an iPad and it appears to work fine (other CSS problems but ...). The way I retrieve this data is by actually adding to my "api" name space a "service" section where the service worker responds and never passes the request to my server.
```
const api = /^\/api\/(service|config|session|profile|approve|gadm)\/(\w+)|(\d+)\/(admin|user)\/(\w+)$/i;
self.addEventListener('fetch', (event) => {
const requestURL = new URL(event.request.url);
if (/^\/api\//i.test(requestURL.pathname)) {
//We have an api call, so deal with it appropriately
const matches = api.exec(requestURL.pathname);
if (matches === null) {
//let the browser do its own thing
} else {
switch (matches[1]) {
case 'service':
//service worker request , lets do it
switch(matches[2]) {
case 'tab':
event.respondWith(
self.clients.matchAll({includeUncontrolled: true}).then(clients => new Response(clients.length.toString(),{status: 200, headers: {
'Cache-Control': 'no-cache',
'Content-Type': 'text/plain; charset=US-ASCII',
} })));
break;
default:
event.respondWith(new Response('', { status: 404 }));//unknown so send a 404
}
break;
case 'config':
...
```
Hurrar - you guys are getting your flow back
Wait. Did we lose it?
It’s looked a little ‘awkward’ vs when you guys are in the studio :)
BroadcastChannel is really easy to polyfill in Safari and older browsers, for those who aren't aware :)
Via what mechanism?
@@jakearchibald I guess we'll never know :(
1:53 Joy-Con 👀
the local storage thing, you said that you can't store objects, but you could just stringify JSON object, correct?
Yep, but that comes with all the limitations of JSON.
@@jakearchibald for example?
@@riddixdan5572 compared to structured cloning, JSON cannot store: circular references, BigInt, Date, RegExp, ArrayBuffer, any of the ArrayBufferViews, Map, Set, Error, ImageData, ImageBitmap, Blob, File… there are probably more I'm forgetting.
@@jakearchibald Hmh, fair enough, but there are always libraries that can imitate it somewhat. but yeah, probably not everything, I guess circular reference would be the easiest to imitate. Can't say the same for other examples you brought tho.
@@riddixdan5572 Oh yeah you can make your own serialisation format if you must. But why not use one of the other storage systems that does all that for you?
Isn't matchAll unsupported on Safari though? Which means that the workers broadcast method will not work on Safari? Please correct me if I am wrong
If you have server data to sync, i really like web sockets for that; keeps all instances on all devices synchronized.
It works pretty much the same as EventSource in terms of synchronising capability.
i do not think i can handle the thumbnail being a mirror of the actual video
What do you think about accessiblity ? Section 501 for example.
Sounds good to me
You mention that storage event is triggered when session storage is changed, but I believe session storage is not shared between different windows and the event does NOT trigger
No, we are talking about the storage event in the context of LocalStorage, not SessionStorage.
Yep. But also, a page and same origin s will share session storage.
if you want to sync tabs across sub domains, you will have to create a JavaScript cookie and do pooling on it. YIKES IK.
I don’t know any other way other than going server side.
I would use s and postMessage for that. Avoids polling.
Who can we lobby to get them working on the ID Bob Server?
Hi, thanks for this video!
We solved the task of synchronizing tabs through service worker, but we came across the fact that sw periodically falls asleep and does not respond to messages from its customers. Please tell me how to proceed in this case and is the estimate of 1.000 correct?
We started using shared workers for synchronization, and it has proven itself perfectly
Sending the service worker a message via fetch or postMessage should always wake it up. If you've found a case where it doesn't, it's a bug. However, if you're expecting the service worker to stay awake when it isn't doing anything… that isn't what it's designed for.
@@jakearchibald No, we do not expect and do not want the worker service to always be in an active state, however, we hoped that the postMessage message from the tab (his client) would wake him up.
Moreover, this behavior is very difficult to catch. Anyway, we switched to shared workers, please tell me how much better this solution is.
Or is it better to deal with the service worker after all?
I like the service worker because it keeps the list of clients always up to date. In turn, in the shared worker, you need to monitor the customers yourself
@@airmust2265 the service worker should definitely wake up on postMessage. Shared worker is good too, but not supported on mobile
@@jakearchibald understood thanks! I will also experiment with the service worker, I will try to understand why he does not come to life in me
Firefox the best browser ever
correct sum, no worries
8:46 Well, you can store objects as json tho
Emrah ATILKAN You can
Only a very specific subset of objects. You can have cyclic structures in JavaScript, but that doesn't translate to JSON. JSON can't handle Maps, Sets, ArrayBuffer/ArrayBufferViews, classes, prototypes... lots of things can get lost when stringifying.
Surma Exactly, and this should be enough for most use cases. Needing to store abstract objects on the client side is a pretty rare scenario. And in some cases you can prepare complex object(s) before the "stringification". But I get your point!
Emrah ATILKAN Well it is still a JSON String though but technically not an object anymore, that’s true. Nevertheless you are still able to store objects, just not directly as objects while being in the storage. Got me there.
IDBObserver would be a great solution to replace RxDB
😂😂😂 thank you for you show.
Local storage ?
I'm missing SharedWorker in this episode!
Well, postMessage should summarize it. And it's mentioned in BroadcastChannel.
BroadcastChannel should have a better score nowadays, given its support.
ahh the beauty of the web :(
You forgot websocket
They were talking about offline ways
It works pretty much the same as EventSource in terms of synchronising capability.
@@jakearchibald can you use websockets to communicate between documents directly?
@@wtho nah
you forgot websocket... for every user create a channel in backend and broadcast to all instances
I guess you'd be doing about the same as SSE
@@sjorsborsoborsobors yeah, the only difference is it isn't broadcast only
@@sjorsborsoborsobors yea, almost the same in terms of pros and cons.
wait who is gone but not forgotten?
I forgot.
Clappy time XD
Https 3143