hey friends with how almost every
JavaScript framework today is
implementing signals I thought it would
be really interesting to actually learn
how signals work under the hood why is
every framework adopting them and to
understand that we're going to go
briefly through the history of
reactivity in JavaScript and then we're
going to implement signals from scratch
to understand how they work to
understand signals we need to understand
the current limitations of reactivity in
JavaScript so for example I can define a
count value and set it to zero and let's
say for example that we want a double
value can say count * 2 and this is
really cool but now for example let's
say that we reassign count 10 and we
want to console log double course double
is going to be zero because it's going
to evaluate only once here right so now
when we open our terminal and now we can
run this you're going to see this is
zero all right so I be thinking okay we
can turn this into a function for
example so now this is going to give us
a Fresh Value each time so now we can
say double and this should be 20 now and
this works great but let's say for
example that we want to do certain
things when count updates so in essence
we want to subscribe to it we want to do
this because this is really tedious for
example now if we change count to 20
again nothing is going to happen if we
run this because nothing is reactive
right so we always have to do this
tedious work now this is going to Output
20 and 40 and to solve this problem
people came up with the Observer pattern
so if we go here to The Observer we can
read the definition of the Observer
Observer is a behavioral design pattern
that lets you define a subscription mean
mechanism to notify multiple objects
about any events that happen to the
object they're observing as you can see
in this example this is the observable
or the subject and these are The
Observers and in this example they're
using mostly classes so you're going to
see a bunch of different examples of
this and there's a lot of variations on
the Observer pattern but basically you
just have these objects or functions
that can subscribe to the observable in
this example they talk about an object
or class which has a DOT update method
on it but this doesn't have to be an
object at all you can just pass a
regular function and we're actually
going to first implement the Observer
pattern to understand the differences
between it and signals even though
signals are based on the Observer
pattern but they're not the same and
also if you want to read The Observer
pattern using JavaScript here you can
see this code example and here is
actually a pretty cool demo so you can
see how we can use the Observer pattern
so when we handle a click or handle a
toggle we actually want to log something
and we want to pop a toast so we can see
in this example how we're going to
notify it and it's going to run the log
and the
toast and signals aren't even a new
thing in 2010 there was this Javas
framework knockout which use signals so
for example if you go here to the
tutorial we're going to actually see
something really familiar let's go to
step two and then we can see introducing
observables so this framework already
had a lot of the concepts about binding
values using observables and Etc so
let's actually just solve this and now
we're going to see when we update to
something and go to next one is going to
update live so how beautiful is this R
and even if we go to the next step
you're going to see there's also other
things here like computers and Etc I
zoom in we have observables and you have
computed values so using this system you
don't actually have to worry about the
plumbing in your code you can just set
this relationships and they're going to
update because they depend on each other
and knockout of course inspired
framework like solid so you can read
this post by Ryan carato the CEO of
signals he didn't invent signals but he
made them popular this is a really
awesome post that explains fine grain
reactivity it just means it's going to
update only what's required so fine
grain reactivity is built from a network
of Primitives and in this case the
Primitive he's talking about is signals
so we actually have this proposal here
which is really awesome so if they
become part of the language the
JavaScript engine can optimize for them
and Etc you can see here is even polyi
that you can try out today and they have
some awesome examples here for example
how you can use them with decorators and
classes so you can also remove a lot of
boiler plates so for example here we
have per class counter and then we can
use decorators like this to make writing
our code easier and there is this
another awesome post from Ry carato
building our reactive library from
scratch this is what I'm going to base
the signals example I took this as an
inspiration and I made it also a lot
simpler because we don't need things
like nested reactivity but I'm going to
post all of these links in the
description if you want to learn more
all right so let's implement the
Observer pattern so here I have just a
simple counter example nothing special
as you can see if I inspected this is
just a regular button set to zero and
that's basically it all right so how can
we implement the Observer pattern and
it's actually surprisingly simple so in
this case here we can have this
observable which can be a class or a
function it really doesn't matter it can
hold a value some logic it's really not
important it has subscribers a subscribe
unsubscribe and update method we're
actually going to see we don't need an
upsubscribe method and then we have
these subscribers so these are The
Observers and then when this observable
updates we can update our count for
example count do increment and then we
can fire off an update so we can notify
our subscribers and this can be anything
right so for example this doesn't have
to be an object this can be just a
regular function we can for example
invoke count. subscribe and then we get
the freshest count value and then we can
update this value inside the button or
if we want we can have another
subscription we can say count subscribe
then we get the freshest count value and
then we can just log the value out so
this is using a onet to many
relationship and the Observer pattern is
the vent driven and you're also going to
hear a lot about this push and pull
system but in this case this is a push
system because we're just pushing an
update and then we do something based on
that so the Observer pattern uses a push
mechanism and one thing worth mentioning
is that you're constantly using the
Observer pattern so for example let's
look at this example you might have
heard of the publish subscribe pattern
and this has different names no one can
agree on this right so there's the
mediator pattern publish subscribe this
is the Observer pattern right so for
example here we have this button ad
event listener which looks really
familiar so we subscribe to The Click
event and then we run some action right
and that's basically using the Observer
pattern so in my code example here I'm
just going to query this button in my
example and then I'm going to L click so
when I open the developer tools and this
is going to just Lo click that's
basically it nothing fancy and as I said
this is really kind of annoying so for
example here we have count here and now
we want to update the value of this
button we can say button inner text and
then we can say Plus plus to increment
the count and this should work but again
it's really annoying and what if
different parts of a app want to
subscribe to this value right so this is
where the Observer pattern comes in and
it's very simple to implement if you
remember what we need to pass in so for
example here we can create a class or a
function we need subscribers the
Subscribe method and an update method so
let's Implement that I'm going to go
here and I'm going to create a
function
observable now what do we need
subscribers and then instead of using an
array I only want unique subscribers so
I'm going to use a set and we can just
say new set that's it and remember we
just need to return two methods so we
need subscribe this is going to take a
function and then we also need an update
method which is going to take the new
value and now anyone can subscribe to
this observable and this doesn't have to
be named observable this can be named
banana count whatever you want and now
we can go here and add this to our
subscribers so I'm going to say
subscribers add and I'm going to add
this function and again this is just a
simple function we're not passing an
object or anything else and the reason I
haven't included an unsubscribe function
because I think it's really easier to
just return a cleanup function so we can
just say return and we're just going to
return a regular function so we're going
to say
subscribers remove the function right so
we don't have to pass it as a reference
or anything else it's just going to get
removed and then to notify the
subscribers and again this can be named
anything you want you're going to see
different names for is notified and Etc
I'm just going to name this update and
then we're just going to Loop over the
subscribers and execute the function so
I'm going to say
subscribers for each function we're
going to execute the function and we're
going to pass the current value all
right so let's export this observable so
we're going to say export and then we
can import it here so we're going to say
import observable from observable that's
it so now we can assign count to be
observable and now we can subscribe to
this count and do whatever we want so
for example we can say count subscribe
and then let's say for example that you
want to pass in a message we can say
message and then we can say console
log message right here and then here
inside of Click let me just comment this
for the time being now we can say count
update and then we're going to send this
message hi all right so now we can save
this and now let's go here refresh
everything so now we should see high
each time that count gets updated and as
you can see this works beautifully so
now anyone can subscribe to this account
and do whatever they want but this
really isn't that useful so for example
we can add some logic inside of the
observable for example we can pass in a
value here and then let's have an
increment method
here so inside of here we're just going
to increment the value that we passed
and then we're going to notify the
subscribers so just by saying
update value we have to use this to
refer to the method that we returning
right so we can say this update and then
we can pass the value all right cool so
now actually here we can pass the
initial value which is going to be zero
and now this is the beautiful part so
now we can yoink this and now we also
going to get the count right so now we
can just go here and we can always get
the fresh as well we now we're going to
subscribe to the count each time count
increments we're going to notify the
subscribers and now we can just assign
this to count and inside of here we no
longer have to call update manually
because we can just say increment that's
it so now each time we increment this
value we're going to notify this
subcribers that the value has changed
and this is going to get updated and now
this is the beautiful part because we no
longer have to do things manually and we
can of course add another subscriber so
for example here we said the inner text
but in this example we maybe just want
to log the value out so we can say conso
count okay increment is not a function
let's see so again let's see maybe it
didn't save so we can go here refresh
everything 1 2 34 and there you go I
forgot to save seeing me right but we
can see everything works great and
remember how we return the cleanup
function so here is how we can use it so
for example we can say here const
unsubscribe and now we can just invoke
this function here and this is going to
do the cleanup so this is going to
remove the subscriber from the
subscribers right so it's saying remove
is not a function and that's because I'm
silly it's not remove it's delete cool
now we can save this and now you're
going to see it's not going to log but
it's going to update the counter because
we ran the cleanup on this subscription
where we just loged the account all
right and this is great but what is the
limitation of this compared to something
like signals where we're going to
actually see when we Implement signals
but for right now you can see that it's
really tedious that we have to set this
subscriptions up ourselves right so for
example let's say that we have some
value here which is double so now how
can we update it so for example here
where we have this subscribe count are
we just going to do this we're going to
say double for example and then we're
going to say okay double equals count *
2 and then we're going to do something
with that or we can even put double here
inside of this observable orable as you
see it's starting to get unreliable
right and it's easy to make mistakes so
what are signals signals are also
observables but they're also called
atoms subjects or refs signals are
eventat and they use a hybrid push and
pull system but what makes signals
unique to using the Observer pattern in
this case here we have a simple signal
which can be a function or a class and
it also has subscribers but unlike the
Observer pattern you use a getter and
Setter whenever you access the value of
a signal then you're going to
automatically add a subscription to the
signal and once you run that code in the
subscription you're going to get rid of
it and then when you update the value of
a signal you're going to run all of the
subscriptions and this happens
constantly and unlike the Observer
pattern here where you just push out an
update like this to all of the
subscribers here I purposely draw these
arrows here so it looks more like nose
right so all of this is connected and
this gets rebuilt each time when you
access or update a signal and a signal
is just something that holds a value
that may or may not change over time so
signals alone are not very interesting
without their partner in crime reactions
so what are reactions where reactions
are the derives effects computed or
whatever else name you can think of for
them so they observe the signal and
rerun each time their value updates so
for example for the count here we can
have a derived count. value time 2 when
we access this value we're going to
create this dependency graph and same
where we're using effects where we just
want to update this inner text value
using count value we're going to update
the dependency graph to have this count
text value and this is basically what
runtime reactivity means as your code is
running you click a button do some
action this entire graph is going to be
rebuilt each time dependencies are going
to be added and removed and this is the
main difference from The Observer
pattern because you don't have to think
about any of this once you set up
signals that's it they're going to take
care of everything else in the case of
having derived values like this they're
also going to get automatically
memorized which means that you're going
to save on having to compute the value
again because you're going to get
computed once it runs and then it's only
going to get updated if that signal
updates all right so let's create a
simple signals implementation I'm going
to create a function which I'm going to
name signal and I'm going to pass in a
value so now we need to keep track of
the signal subscribers so I'm going to
say con
subscriptions new set and now we need to
return a getter and a Setter and you can
do this however you want you can create
a read and write function return a tuple
or you can just return a JavaScript
getter and Setter so I'm going to do
that I'm going to say return get
value and I'm going to say set
value for this we just need to return
the value that's it and basically here
we're going to receive the updated value
and now we need to update the value
to update it all right and that's
basically it but as we read before this
is really useless because a signal is
nothing without a reaction so for
example if we export this signal and now
we can go here and let me just import it
import signal from signals that's it
cool so now we can go here and we can
say let
count signal and now here we can say
count. Val let's go back to our example
and now we're going to see it log zero
but of course as I said this is useless
because we need effects and arrives to
make signals useful and what do I mean
by that for example here in this ad
event listener let's say for example
that whenever we update the value of
count so let's say count value Plus+
whenever this happens we actually want
to reactively run some effect or
whatever right and let me actually just
save this so this is going to increment
the value and then we want some effect
here we can just make something like
this and then we can say Ono loog count
do value and because here we have this
signal inside of here when we read this
signal we're going to add it as a
subscriber or a dependency this effect
and we're going to run it and this is
going to happen every time and this is
why signals are so awesome because this
happens dynamically all right but enough
talking let me actually show you how
this works so for example here we have
this effect and let's also say
export function effect we're going to
pass in a function this is really
similar to do subscribe right and then
we're actually going to you need a value
to track the current running subscriber
you're going to see this name context
and whatever but I'm just going to say
let subscriber I'm going to set this to
null and now we're going to set the
subscriber to the function we want to
run the fact immediately and then when
we're done this is Superfluous but let's
just keep it clean and we're going to
set the subscriber to null all right so
now what's going to happen because look
at this inside of this effect this way
signals are so awesome because we're
saying count. value we're going to add
this function here we're going to invoke
this immediately so what happens when we
invoke this function we're going to run
count. value and what happens when we
read the value well right now it happens
nothing but let's add it to the
subscriptions so this is going to get
added to the subscriber at the top and
now here when we read the value right
this is the beautiful part we can say
if subscriber we're going to add it to
the
subscriptions subscriptions
add subscribe
boom and now the only remaining thing to
do is to run all of those subscriptions
right so now you can see here since we
invoked count out value we're going to
add the subscription but now here in our
event listener we're actually
reassigning the value so now this part
kicks in right how beautiful is this R
so now we just need to run the
subscriptions all right so now we can go
subscriptions and then we're going to
say for each function and then we're
going to invoke the function and of
course we need to import effects from
here let me just save everything refresh
let me see 1 2 3 4 how beautiful is this
friend and let's of course add another
effect so here we have this effect but
let's say for example we want to update
the HTML each time the value updates
well easy peasy lemon squeezy friends we
can just say button inner text is going
to be count value and now we're going to
add another effect so now when we save
it and go back to our example 1 2 3 4
and and also creating a derived signal
isn't really that hard either so we can
go back here to our code and now we can
just say export function derived we're
going to pass in a function and that's
basically it all right so to create a
derived signal we need to create a
signal and then we're going to wrap it
inside of effect and then we're going to
return the signal and that's basically
it so I'm going to say const the arrived
it's going to be a signal and then again
we can just use an effect and let's
update derive do value is going to equal
the result of the function and then we
just need to return the derive signal
just save this we can go back here to
our code we can say let double and of
course let's not forget to import it say
let double derived we can pass in a
function here we can say count do value
* 2 and now instead of saying count do
value here we can just say double dot
value because it's just a signal right
and if I save this and refresh you're
going to see 2 4 6 8 10 and so on and of
course you can do other things inside of
an effect we can say for example if
count. value is higher than 10 then
we're going to console log dangerously
high and then let's just reset the
value now we're going to see dangerously
high is going to reset to zero so
actually we can even let's say count
value and we can add as many effects as
we want so we can go here let's just say
that you're going to to log
double boom just like that so we're
going to see once you go over 10 going
to say dangerously high oh and of course
this isn't button in our text we just
want to console
log double do value now when you
refresh you're going to see everything
works as expected as you can see this is
the main difference between the Observer
pattern and signals because signals once
you set things up you don't have to
think about it
anymore signals may look like magic but
they're relatively simple all right so
that's it if you like what your scene
don't forget to like And subscribe and
you can also support me by becoming a
patreon thank you for watching and catch
you in the next one peace