Rethinking Asynchronous JavaScript

Event Channels

Kyle Simpson

Kyle Simpson

You Don't Know JS
Rethinking Asynchronous JavaScript

Check out a free preview of the full Rethinking Asynchronous JavaScript course

The "Event Channels" Lesson is part of the full, Rethinking Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:

Kyle spends a few minutes explains how CSP can be applied to DOM events. He also demonstrates how he uses CSP inside of the Asynquence library.


Transcript from the "Event Channels" Lesson

>> [MUSIC]

>> Kyle Simpson: Member are from a vent friend from the reactive side. Here's how we could set up an event that listens for Dhamma vents. I mean a channel that listens for dominance. I set up a channel on line two I attach a click handler to it and you notice on line 4, I call put Async.

Why am I not calling put? Well, cuz I'm not inside of a generator right now. I'm inside of a click handler, which is a plain old normal function. That putAsync would return me a Promise if I wanted to listen to be told that the put had completed. But maybe I don't care whether it completes.

I'm just gonna put the event object into the channel. And then there is a real legitimate go routine that's waiting to hear for that message on line 12 he's trying to take from that channel. So he just spinning in a while true loop and each time you click that or each time you do that event.

I'm going to take I'm going to get notified by that by being able to take from the channel and I'm gonna print it out. So what event am I doing, mousemove. But what this means is every time the mousemove event fires as I move my cursor around on this element, I'm gonna send a message down the channel that's the event object and print out the x, y location in the console.

So we gonna adapt to user interface elements by having our events fire and pushing things down a channel. Does line 4 look an awful lot like what we did with observables? We had a stream and we were pushing events into a stream and somebody else was taking the events off the stream and observing them.

Is very similar concepts here. The major difference between what we're modeling here and what we model with observables major difference is back pressure, cuz we can model that I don't want you to send me anything else until I'm ready to take it. That comes for free. We don't have to do any extra work.

We don't have to convert our observable from hot to cold to signal that, or anything crazy like that. We just don't take from the channel and that's an automatic built in back pressure.
>> Speaker 2: So when you do take would you get the most recent mouse event? Or would you get it?

>> Kyle Simpson: Yeah, in this case?
>> Speaker 2: Yeah.
>> Kyle Simpson: Every time the event fires, we're going to be putting something into the stream. So you'd be taking them as fast, and they could be piling up faster. But you notice we don't have any timeouts here, so we're going to take them as fast as we possibly can.

>> Speaker 2: So putting putAsync then overriding the previous one, is that the idea?
>> Kyle Simpson: No.
>> Speaker 2: If you're not matching every single one, right?
>> Kyle Simpson: So every time it's going to try to put onto the channel, it's going to say I can't put onto the channel yet because somebody is not ready to take it yet.

So I'm going to have, let's say a bunch of mouse moves happened, a 100 mouse moves happen, but the go routine had never fired a take yet. I have 100 separate waiting Promises that were all in order going to try to push their event down the stream but none of those events had been put on the stream yet until the first take happens.

So if I move my mouse real fast and then this go routine happen. He would get all of those events and print out all 100 of them. That's not throwing any events away. It's important to note that some of the things here don't map perfectly to observable so for example throwing away messages that we don't care about you're going have to use something like alts.

If you want this notion of being able to have channels that you're not that you're sending stuff down that nobody is on the other end listening to. You can make channels into having a buffering mode so channels can have more than buffer size one. So you could make them buffered and say I want to take ten of that sort of time before I start listening.

Lots of variations.
>> Kyle Simpson: Just real quickly, just show you, CSP. I ported the same mechanism into asynquence, again, so you don't have to go learn some other library. You can do it all with the same library. You put go routines into runner. That's how you do it. So I have ASQ., basically ASQ.

In front of every one of those things that you've already seen. It's the exact same APIs that are in the library but the namespace has ASQ. in front of all of them. Otherwise, it's exactly the same concept.
>> Kyle Simpson: I almost skipped over an important detail. Remember you were asking earlier about global variables.

I don't like the notion of having global variables. So I automatically created a channel for each go routine. There is one channel created that they all get reference to. So they automatically have at least one channel that they can all communicate on. And if you wanna make more channels you can make channels and send them over the channel.

So you don't have to use any global variables at all. That's one difference with my implementation versus the others.
>> Speaker 3: In case, this ch is created for free or-
>> Kyle Simpson: It's created automatically by async ones.
>> Speaker 3: Not created somewhere else?
>> Kyle Simpson: No it's created passed in for you.

Because the assumption is every body is gonna need at least one channel so let's go and create want to give it to you, instead of making you make your own.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now