JAKE: It's going to be good. It's going to be great. SURMA: It's going to be great. Yeah, where's the-- you
told me to be more euphoric. Come on, let's-- JAKE: Well-- SURMA: --get the energy up. JAKE: --this is not broadcast. This is, you know-- SURMA: Oh. JAKE: OK, here comes-- here comes clappy time. 3, 2, 1-- [CLAP] [MUSIC PLAYING] So OK-- SURMA: So. JAKE: --lists of things
are pure clickbait, right? It works, doesn't it,
when you say, like-- SURMA: Oh, you mean
like, the 10 things that you can do to be
a rich-- number four will blow your mind. JAKE: Yeah, and like, that
stuff, I know it's clickbait, but it still works on me. I can't-- I just
can't stop myself. So I thought, I'm going to-- I want to get in on that
tasty, tasty click action. So this is 3.143 ways to
synchronize across documents. I'm actually going to talk
about six things, but-- SURMA: This is
annoyingly far off of pi. Like, couldn't you
have made it 3.141? JAKE: Yeah, well, no. No, I decided not to. But I-- that-- do you know what,
I noticed that exact same thing as well. And that did bug me. And I feel-- SURMA: But also, I like that
you never use this font. You used this as your
clickbait font, I presume. JAKE: Yeah. Yeah, and it's the
only time I'm going to be using it in this
presentation as well. So enjoy it. SURMA: Good. JAKE: Enjoy it right now. Yeah, I used some
decimals, because I'm not-- of the things that I'm going to
show, I'm not sure all of them count as one complete way. So I've docked a few
points here and there. So OK-- SURMA: Well, when
doing clickbait, at least do it fairly. JAKE: Exactly. Yeah, I do have some
principles-- some. So be prepared for a shock. Did you know-- SURMA: Mm-hmm? JAKE: --that you can have
multiple tabs open to a page? SURMA: Dun-da-da. JAKE: Mm, I know. SURMA: It's actually
really annoying. Because whenever you write your
service worker update code, that's the case that makes
everything a lot harder. JAKE: Yes. Well, not just that,
it's also the overlap between one page refreshing. There's a kind of time when
both pages are somewhat alive. Or certainly, the
request for the new page is going out while your page--
anyway, topic for another day. The thing I wanted to
talk about is page state. Because while some
state is in your page, but some application-level
state is across those tabs-- like login state, right? You log in in one tab. You would now be expected to
be logged in in another tab. But quite frequently,
a lot of sites don't do anything about this. SURMA: No, I think
barely any site-- I don't think Google
sites do that. JAKE: Well, that's--
shame on them, I say. And this is worse
for single-page apps. Because in a multi-page
app, your next navigation is going to pick it up, right? SURMA: Yeah. JAKE: But in a
single-page app, it might be around a lot longer. So these differences
in state are going to become more
and more noticeable the longer two tabs are alive. There's also client
side state stuff. Like, if you've got a dark
mode toggle on your site, is that per page? Or is that per-- for your application? There's this. So remember this,
when we built the-- SURMA: I remember this. JAKE: --dev server website? SURMA: We wrote this. JAKE: I was really
proud of this. Because this is the
one thing I really wanted from any
other global event. And so it's, at
times, untoggled. Like, tell me the
times where I am, or tell me the times
where the event is. Because if you're going to
the event, you want to know-- you know, it's San
Francisco time. SURMA: When do I have to get up? JAKE: Exactly. And if you're watching
at home, again, when do I have to get up? It's probably going to
be a less sociable time. SURMA: Or how long do I
have to not go to sleep? JAKE: Yes, that is-- that
was mainly the difference. So yeah, you want--
if you, in one tab, change the time zone--
because this is going to be used in multiple pages. You want it to be
updated everywhere. So how do we do
this kind of stuff? SURMA: Did we do that? JAKE: Yeah. Yeah, I did. SURMA: Oh, didn't know. JAKE: And we'll talk about-- SURMA: That's cool. JAKE: --the way
I did it as well. Let's go through a number of
different ways of doing stuff like this. Here's number one. There you go. Post message-- job done. That's one way of doing it. SURMA: How do you know
your other window? I guess a service worker
knows all the windows. But-- JAKE: Ah, that's correct. You don't know
the other windows. Because the only way you'll get
one of these is if you have-- if you do window.open()
or if it's an iframe. So I'm going to have to dock
a load of points for that, I'm afraid. This is not a proper
method, is it? SURMA: It's an eighth
of a method, apparently. JAKE: Yeah, well-- yeah. But also, it has
some good parts. Like, you can-- the
stuff you can transfer, it could be not just string
data, not even just JSON data. It can be binary data, blobs. You can have circular
references in your objects. It's a structured cloneable,
so it supports all of that. SURMA: Have you-- have
you heard of Comlink? JAKE: Yes, and I'm sure
Comlink can help here as well. And I should say that
this is the only method we're going to look at here that
actually works cross-origin. So I'm actually going to give
it some points back for that. So it has specific
use cases, but like you said, not generally useful. It's good at what it
does specifically. But for keeping state across
a whole app, it's just 0.248 of a way. I would say I don't have
time to go through the very complicated and
scientific scoring system that I'm going to be using here. But just trust me that it is-- SURMA: Just trust you that this
is absolutely deeply thought out and completely accurate. JAKE: Absolutely. Absolutely. If I did the same test
again, the same numbers would come out. I've not just picked
these out of my-- how dare you. How very dare you even suggest-- SURMA: You picked them
out of your what, Jake? Where did you pick them? JAKE: All right, let's
leave that behind. Next one-- this is event source. So this is a persistent
server connection. There's other ways
of doing this. You could use fetch,
fetch streams. Have you heard of them? But that doesn't work in Edge,
annoyingly-- well, old Edge, sorry, in the old Edge engine. And there's web sockets as well. SURMA: And you need your server. I mean, come on,
this needs a server. JAKE: And this needs a server. So yeah, that's-- SURMA: Don't like it. Don't like it. JAKE: Well, do you know
what, you're right. Because if you've
got eight tabs open, that's now eight
connections you're keeping, and the same data being
sent to you eight times. So I'm sorry, going to have
to dock some points for that. That's no good, is it? But it does mean you can
communicate cross-device, which is pretty good. SURMA: How do you know
that events sources are coming from the same client
on the server site reliably? JAKE: Well, you-- cookies. So using cookies,
you'll have state. You'll know the login. SURMA: Fine. JAKE: Yeah. I mean, sometimes
you don't need that. Like, I don't know, I
find it really satisfying if I close an issue or merge
an issue on GitHub on my phone, and I see it happen
on the screen as well. It's like, whoo-hoo,
that's good. SURMA: But that's public. OK, I was still thinking in
the time zone thing, which is an inherently personal
adjustment, while something like an issue, that's, quote,
unquote, "global state." So that makes sense. Yeah, OK, I'm with you. JAKE: Yeah. I'm actually going to
give it a few points back. Because it's useful for-- you could do some smart
cross-device stuff. But yeah, it's very specific. And yeah, it's a shame that
we don't really have a way, right now, to sensibly
dedupe a connection. So if you find that you've
got eight tabs open, you kind of want one
to be the main tab and then do a different
method of communication to give that information
to the other tabs, shared worker is a
great way of doing this. But it's not well-supported SURMA: I was waiting
if I should-- if I can bring up shared worker
or if you have it in here. Because that is the thing that
I wanted to use for my actor model stuff as well. But it's so horribly
badly supported that it's just not
a realistic option. JAKE: I literally just
thought of another thing you could use for this. The Web Locks API,
you could have one thing set up a connection
and create a web lock. And then the other
tabs will wait on that web lock to expire
before they try and do it. I don't know, there's probably
some raised conditions in there. Anyway, I haven't thought
about it properly. So I'm going to talk
about it anymore for fear of embarrassing myself. Here's another one. This is like, when you change
local storage or session storage, all the other
windows, they get this event. SURMA: I did not know this. JAKE: I think this
is really cool. Because you get the
old file, the new file. You even get the URL of the
page which made the change. SURMA: Can local
storage store objects? JAKE: No, it can't,
just text data. So I'm going to dock some
points for that reason. But it's fine for
small bits of data. You could also use it-- and
I've done this before-- use it as a signal just to say
this thing's changed, even though the data is
actually somewhere else, like IndexedDB db or cache API. I can use just a little-- SURMA: I think this would've
been useful for my actor model thing. Because what we ended up doing
is using IDB and polling it. JAKE: Ah, oh. SURMA: "Pulling" is the
word-- not polling, pulling. JAKE: Yeah, still, oof,
that's harsh, yeah. So one reason you might not
have used it in your actor model is it only works in a
window, not a worker, because local storage, right? SURMA: Yep, that would
make it a non-starter. JAKE: Yeah, exactly. So let's dock some
more points for that. Although that hasn't been a
problem in practice for me where I've used
this in the past. This is actually how I
did the time zone change. Because it was only ever
reflected in a page. SURMA: That makes a
lot of sense to me. JAKE: So I used it for that. And it was dead simple. If you're only dealing
with dedicated workers, you could have the page
here, this event, and then post message the
worker, whatever. SURMA: True. JAKE: But my main
problem with this is it only alerts other
windows to the changes, which is a little bit of a pain. So in this case, I've got
another component on my page. And it's listening for
this event as well. But if the other
component updates a value, my component's not
going to hear about it. Because it's only going
to tell other windows. SURMA: Oh, it doesn't-- you don't get an event
on your own window, OK. JAKE: Exactly. SURMA: Yeah, that's annoying. That is annoying. JAKE: Yes, that's a problem. So yeah, I'm going to
dock some more points. It's still really useful. But I'm going to say this
is like 0.763 of a method according to my calculations. OK, let's keep going. Broadcast channel-- SURMA: Ah, love it-- JAKE: Love it. SURMA: --if it was real. JAKE: Yes. It is real. This is real. You use this today. SURMA: Barely. JAKE: But one of the
nice things about this is it's structured
cloning, which is great. It works in workers,
which is great-- so all different kinds
of objects and whatever. But also, it will message other
channels on the same page. It will message itself, but it
will message any other channels of the same name. So you don't have that
problem that I showed before. It just works around that,
which is really nice. But-- and I think you were
slightly alluding to this-- it's not symbolic
in Safari, is it? SURMA: It's not. JAKE: And that's the
only modern browser that doesn't support it. Chrome was late to
the party with this. It was in Firefox for a while
before it reached Chrome. SURMA: True. JAKE: But we've had it
for a few years now. And this is top of my list of
things I really want in Safari. Because it's just--
yeah, anyway. I'm not over it, but we'll
move past it for now. Service worker-- so
this listens for events that are sent by the service
worker to other clients. So this works in workers. It's structured cloning again. A little bit more
complicated, because you have to do things manually
when it comes to sending. SURMA: Yeah, the
service worker side is a bit convoluted as well. JAKE: Yeah, so here I'm post
messaging to the service worker to say, hey, please
broadcast this for me. And then the service worker
is going to pick up that event and then broadcast it back. This is useful in the
multi-component case as well, because you get to
decide whether it posts back to the same client. And I tend to. I always post back
to the main client. In fact, I use that
as my source of truth. Like, one component will send
the data to the service worker. But then it won't
apply that data change until it hears back about it. And that works in a
multi-component web components case. But you know, that's preference. You get to do-- get to
do whatever you want. So that's one way of doing it. And I'm actually going
to leave that at 1. Because that's my favorite
method when I need all of those features. SURMA: And the post
message-- sending something to the service worker will wake
it up in case it's been killed. And it will have, always,
a correct and complete list of all the clients, right? JAKE: Yes. Yep, when you call
match clients, that's when it will go
and get all of those. By default, it's only
controlled clients. But there's an option to say,
give me the uncontrolled ones as well. By default, it's only pages. But there's another
option where you say, I want the workers as well. So yeah, that's all in
your control and up to you. One last one-- here we go. Oh, ho, ho, ho,
ho, look at this. This is-- SURMA: Are they finally a thing? JAKE: --an IDB observer. SURMA: Yes. JAKE: So you create a callback. And then you say what
you want to observe. Works in workers. You get a complex type, because
it's all of the IDB stuff. It has everything. So you can just
use your IndexedDB as the central store
for your state. And then your components
can listen for when the bit they care about
actually changes. So it is a way for-- SURMA: And it's not supported. JAKE: It's just an-- it's just an explainer. I think there's a partial
experimental implementation in Chrome. And worse, this explainer
hasn't been touched in 2017-- SURMA: Oh-- JAKE: --which is a lot
of years in web years. SURMA: You got me hopeful
there for a second, right? JAKE: I know. SURMA: Because I knew
they were working on it. And I was like, is it happening? Are they a thing? JAKE: I just wanted to play
with your emotions a bit there. But [INAUDIBLE],, we both
really want this, right? SURMA: Yes. JAKE: This is what-- this is
how we want to build apps. We want to be able to store
all of the data in IndexedDB and then use observers to--
so one component's like, I only care about this bit. I only care when
this thing changes. So just let me know. SURMA: Yeah, imagine if
you could put your redux state into IDB and have all
the other components just subscribe to it
via IDE observer. And if the page reloads,
it doesn't matter. All the state is still there. It's like, it would be so
many things I wanted to try if they are actually feasible. JAKE: Actually, I would love to
also have a session IndexedDB store as well-- SURMA: Yeah. JAKE: --so a way that you
would say, I want this, but just for this tab. And if this tab closes,
[INAUDIBLE] data. And that also means-- ah, it depends. Again, depends who
you ask whether this is the spec behavior or not. Session storage, in some
cases, survives a tab crash. So tab crashes--
reload, and you've only lost whatever happened
before your last commit to IDB, which is
great as well, right? SURMA: Yes. JAKE: I know I'm not-- I'm ending on a sad, sad story. SURMA: On a 0.005. JAKE: That's all I've got. Hopefully, one day, we get this. But in the meantime, yeah, I
think the service worker way-- SURMA: Now in thinking,
do your numbers actually add up to 3.145? JAKE: I hope so. SURMA: 3.143. JAKE: I hope so. Because I sort of panic
added it up at the end. But it is entirely
possible I missed-- SURMA: But you did
at least add them up. If it was me, I probably would
have just written math.random on every slide. JAKE: I definitely
attempted to add them up. Whether I got it right I'm
not, I'm-- do you know what, I reckon we'll hear about
that in the comments. SURMA: Oh yeah, we will. And you will get told
off if it's not correct. JAKE: It's all I deserve. [MUSIC PLAYING] Just one second, because
I'm really worried. Because I thought my fan
went off during that episode. So I just want to double
check that everything actually recorded. I don't have any error messages. And I have 17
minutes of recording. Yeah, yeah, yeah, yeah,
it's all recorded. Thank Christ for that.