eventemitter_通过准将Fluffykins学习Node.js第二部分:事件,EventEmitter和事件循环

eventemitter

by Mariya Diminsky

通过玛丽亚·迪明斯基(Mariya Diminsky)

通过准将Fluffykins学习Node.js第二部分:事件,EventEmitter和事件循环 (Learn Node.js with Brigadier Fluffykins Part II: Events, EventEmitter and the Event Loop)

Welcome to Part II of Learn Node.js With Brigadier Fluffykins, a series created to help you easily understand Node.js ❤

欢迎使用Fluffykins准将来学习Node.js的第二部分,该系列旨在帮助您轻松理解Node.js❤

In Part I Brigadier Fluffykins and I introduced Node.js, what you can build with it, async/sync concepts. I walked you through install, and together we created your first server.

第一部分 Fluffykins准将中,我介绍了Node.js,您可以使用它构建什么,异步/同步概念。 我引导您完成安装,然后我们共同创建了您的第一台服务器。

It was glorious:

这是光荣的:

Today’s lesson will cover:

今天的课程将涵盖:

  • Why Node.js is an event driven language, and how this is important for asynchronous behavior

    为什么Node.js是事件驱动语言,以及这对于异步行为的重要性
  • How events in the DOM are similar to events in Node.js

    DOM中的事件与Node.js中的事件如何相似
  • How the Event Loop processes requests

    事件循环如何处理请求
  • Creating custom events using the EventEmitter

    使用EventEmitter创建自定义事件

事件驱动编程很棒 (Event Driven Programming is Awesome)

Since Node.js is single-threaded, in order for it to create concurrency and not be painfully slow — as the traditional client server model explained in Part I — it uses events to listen for requests.

由于Node.js是单线程的,因此要使其并发且不会太慢(如第一部分中所述的传统客户端服务器模型),它将使用事件来监听请求。

This is different from say, Apache, a web server that uses multi-threaded HTTP. For every request Apache receives, it creates a new thread for handling it. This means that yes, while you can have more than one process running at the same time via threads, the downfall is that results from all the requests have to come back before serving the page.

这与Apache(使用多线程HTTP的Web服务器)不同。 对于Apache收到的每个请求,它都会创建一个新线程来处理它。 这意味着是的,尽管您可以通过线程同时运行多个进程,但失败的原因是,所有请求的结果必须在提供页面之前返回。

On the other hand, Node.j’s event driven architecture allows for multiple requests to be processed on a single thread. For example, once a request event is triggered, callbacks and promises process these requests asynchronously.

另一方面,Node.j的事件驱动架构允许在单个线程上处理多个请求。 例如,一旦触发了请求 事件 ,回调和promise将异步处理这些请求。

This means if you have multiple requests coming in and request A is still doing its thing, request B will start fetching the results — the outcome being either request B responds to the client before request A or at the same time as Request A.

这意味着,如果有多个请求进入并且请求A仍在执行任务,则请求B将开始获取结果-结果是请求B在请求A之前响应客户端,或者与请求A同时响应。

Since everything is processed faster, the client has a better user experience. Lets discuss this in more detail further in the lesson.

由于所有内容的处理速度更快,因此客户端具有更好的用户体验。 让我们在本课中进一步详细讨论这一点。

There are some downfalls to Node.js’s concurrency model but we’ll be covering this in the next few lessons.

Node.js的并发模型有一些缺点,但是我们将在接下来的几课中介绍。

DOM中的事件类似于Node.js中的事件 (Events in the DOM are like Events in Node.js)

Think of events this way: just as events interact with DOM objects, many objects in Node.js emit events.

以这种方式考虑事件:就像事件与DOM对象交互一样,Node.js中的许多对象也会发出事件。

If you’ve done any type of DOM manipulation with JavaScript, then you understand that the DOM can have event listeners such as click, dblclick, submit, keydown, keyup and so on. Once triggered, the event is handled with a callback.

如果您使用JavaScript完成了任何类型的DOM操作,那么您就会了解DOM可以具有事件监听器,例如clickdblclickSubmit ,keydown,keyup等。 触发后,将使用回调处理事件。

For example, when you set up a click event, you can have a callback say: “when something is clicked, turn the third div blue!”

例如,当您设置一个click事件时,您可以有一个回调说:“单击某项时,将第三个div变蓝!”

Here’s a coded example.

这是一个编码示例。

In your index.html file:

在您的index.html文件中:

In your main.js file:

在您的main.js文件中

And, if you want to test this out in your own browser here’s some CSS. This should go in style.css:

而且,如果您想在自己的浏览器中对此进行测试,则可以使用一些CSS。 这应该放在style.css中

When the client clicks the button, our click event is triggered, and our callback does something to the DOM. In this case, it turns the third div blue and changes the text inside the button.

当客户端单击该按钮时,将触发我们的click事件,并且我们的回调会对DOM做一些事情。 在这种情况下,它将第三个div变为蓝色并更改按钮内的文本。

Like the request event in Node.js, when the client clicks a button, it’s as if they are sending a request into the main.js file where the click event is listening — just as the request event would listen in for incoming requests.

就像Node.js中的request 事件一样,当客户端单击按钮时,就好像他们正在将请求发送到click事件正在侦听的main.js文件中一样,就像request事件将侦听传入的请求一样。

Then, just like the response event would respond to the client with some information inside the callback, the callback of the DOM’s click event responds by changing the background color of the third div. It also changes the text in the button inside the html file.

然后,就像响应 事件将在回调中使用一些信息来响应客户端一样,DOM的click事件的回调通过更改第三div的背景色来响应。 它还会更改html文件内按钮中的文本。

The main difference between events in Node.js and events in the DOM is that DOM events stay primarily attached to the DOM object — on the client-side — while events for Node.js are focused more on the relationship between the client and the server.

Node.js中的事件与DOM中的事件之间的主要区别在于,DOM事件主要保持附加在客户端的DOM对象上,而Node.js的事件则更多地关注于客户端和服务器之间的关系。 。

Node.js emits events from objects — such as the web server object(http.createServer). Lucky for you, you’ve actually already used events back in Part I in STEP #1.5!

Node.js从对象发出事件,例如Web服务器对象( http.createServer)。 幸运的是,您实际上已经在步骤1.5的第一部分中使用了事件!

During this step, you saved the web server object in it’s own variable and listened for incoming requests via the request event attached to the http.createServer object in the first parameter.

在此步骤中,您将Web服务器对象保存在其自己的变量中,并通过第一个参数中附加到http.createServer对象的request事件监听了传入的请求。

Underneath this object is the EventEmitter constructor, which we’ll learn about very soon. For now, review the code we set up in Part I and see if you have a better grasp of what’s going after our event explanation.

该对象的下面是EventEmitter 构造函数 ,我们将很快对其进行了解。 现在,回顾一下我们在第一部分中设置的代码,看看您是否对事件解释后的情况有了更好的了解。

Here it is again for reference:

这里再次供参考:

事件循环 (The Event Loop)

Ok so you have a basic understanding of events and how they relate with Node.js but how does Node.js actually work under the hood?

好的,您对事件及其与Node.js的关系有基本的了解,但是Node.js到底是如何工作的呢?

The first thing Node.js does when it reads your code is subscribe events you used, such as request, listen, connection or close. Once it’s done, it goes into the Event Loop and listens for these events continuously inside a single thread.

Node.js读取代码时要做的第一件事是使用的预订事件,例如requestlistenconnectionclose。 完成后,它将进入事件循环,并在单个线程内连续侦听这些事件。

For example, in the server we previously created above, it’s only listening for the request event and thus the Event Loop thinks:

例如,在我们之前在上面创建的服务器中,它仅侦听请求事件 ,因此事件循环会认为:

“Have any requests come in?”

“有任何要求吗?”

“How about now?”

“现在怎么样?”

“…. “

“……。 “

“Now?”

“现在?”

“Now right?”

“现在好吗?”

No worries, Node.js’s single threaded Event Loop is not Jules Winfield. It’s actually just patiently waiting and listening for events that it previously subscribed to in the background.

不用担心,Node.js的单线程事件循环不是Jules Winfield。 实际上,它只是耐心地等待并监听先前在后台订阅的事件。

If a request does arrive, it triggers the request event and runs the callback we wrote — in our case, the mini html inside the end method in our previous server example. Also be aware that events can trigger other events.

如果请求确实到达,它将触发请求 事件并运行我们编写的回调-在我们的示例中,是我们先前服务器示例中end方法内的mini html。 另请注意,事件可能会触发其他事件。

But what if multiple requests come at the same time? Like the request and close event? The event loop will process these events one at time. So first the request event will be processed and then the close event. While they are being handled they don’t block more events from coming in. If they did, our code would run twice as long.

但是,如果同时有多个请求怎么办? 喜欢请求关闭事件吗? 事件循环将一次处理一次这些事件。 因此,首先将处理请求 事件 ,然后处理关闭 事件 。 在处理它们的过程中,它们不会阻止更多事件的进入。如果这样做,我们的代码将运行两倍的时间。

让我们进一步深入了解这一切意味着什么 (Lets dive further into what this all means)

So when we say JavaScript is single-threaded we are saying it has only one Call Stack — something that keeps track of functions that will execute in your code. Each golden bar represents a function inside of the Call Stack. Last function added on top is the first function that executes and pops off.

因此,当我们说JavaScript是单线程的时,我们说的是它只有一个调用堆栈 -可以跟踪将在您的代码中执行的函数的东西。 每个金色条代表“ 调用堆栈”内部的一个函数。 最上面添加的最后一个函数是第一个执行并弹出的函数。

If JavaScript was a synchronous language, and we had two requests coming in what do you think would happen? We would have to wait for the result of the first request to come back before we could process the second request. This means that the first request would stay in the Call Stack, blocking any other requests from coming in, until it’s necessary results returned.

如果JavaScript是一种同步语言,并且我们有两个请求,您认为会发生什么? 我们必须等待第一个请求的结果返回,然后才能处理第二个请求。 这意味着第一个请求将保留在调用堆栈中 ,阻止其他任何请求进入,直到返回必要的结果为止。

Once the results are retrieved, the first request “pops off,” and only then would the second request go into the Call Stack and get executed:

检索结果后,第一个请求“弹出”,然后,第二个请求才进入调用堆栈并被执行:

JavaScript achieves its concurrency model by storing asynchronous functions somewhere else while other tasks that are much faster run first. Then, when our asynchronous function receives what it needs, it eventually executes. At least that’s the gist of it.

JavaScript通过将异步函数存储在其他位置来实现其并发模型,而其他更快的任务则首先运行。 然后,当我们的异步函数收到所需的内容时,它将最终执行。 至少这就是要点。

Lets dive deeper now that we know about the Call Stack.

现在,我们对调用栈有了更深入的了解。

When an asynchronous function with a callback or event comes into the Call Stack, it automatically moves into the Web API. The Web API is where events subscribed to the Event Loop are stored. They await orders from the Event Loop, which listens if any of the events are called.

当具有回调或事件的异步函数进入调用堆栈时 ,它将自动移入Web APIWeb API是存储订阅事件循环事件的位置。 它们等待来自Event Loop的命令,该事件将侦听是否调用了任何事件。

Once someone triggers an event, for example, the request event, the callback of this event gets sent into an event queue. This queue is also called the callback queue or just task queue.

一旦有人触发了一个事件(例如request事件) ,该事件的回调就会发送到事件队列中 。 此队列也称为回调队列或仅称为任务队列。

The reason we have multiple names for the queue is because the same process that happens for events happens for asynchronous functions — or methods — anything that has a callback, including DOM events and event functions not part of native JavaScript like ajax and setTimeout(Yep, they’re part of the Web API, not JavaScript).

我们为队列使用多个名称的原因是,事件发生的相同过程发生在异步函数(或方法)上,即具有回调的任何事件,包括DOM事件和非原生JavaScript的事件函数(如ajaxsetTimeout (是的,它们是Web API的一部分,而不是JavaScript)。

Now the last thing that happens is the callback of the request event will wait inside of this event/callback/task queue for the Call Stack to empty. This has something to do with the way JavaScript processes memory — so basically just know once we get to this stage we have to wait until all the functions still running empty out before we can add the callback into the Call Stack and process it.

现在,最后发生的事情是请求事件的回调将在此事件/回调/任务队列内部等待,以使调用堆栈为空。 这与JavaScript处理内存的方式有关—因此,基本上我们只知道一旦进入这一阶段,就必须等到所有函数仍然用尽之后才能将回调添加到调用堆栈中并进行处理。

Here’s a visual demonstration of everything we just explained:

这是我们刚刚解释的所有内容的直观演示:

  1. JavaScript scans your code and stacks functions, events, and everything else on the Call Stack.

    JavaScript会扫描您的代码,并在Call Stack上堆栈函数,事件以及所有其他内容。

  2. The golden bars below are regular, non-asynchronous, functions. The last pink and green bars are two request events. These events are subscribed to Event Loop (played by Brigadier Fluffykins) and wait inside the Web API to be called.

    下面的金色条是常规的非异步功能。 最后一个粉红色和绿色的条是两个请求事件 。 这些事件被订阅到事件循环 (由Brigadier Fluffykins播放)中,并在Web API中等待被调用。

  3. As the events wait, other functions are executed on the Call Stack.

    当事件等待时,其他函数在Call Stack上执行。

  4. Once an event is triggered, the Event Loop hears it and that particular event’s callback moves into the queue. Although, since this is the request event, it would first wait for any results it needs. And only then does it send the callback over into the queue.

    触发事件后, 事件循环将听到该事件 ,并且该特定事件的回调将进入队列。 尽管由于这是request事件 ,所以它将首先等待它需要的任何结果。 然后才将回调发送到队列中。

  5. While there are still functions running and being executed on the Call Stack, the events have to wait for the Call Stack to empty in order for them to run. Brigadier Fluffykins lets them know if it’s A-OK to move into the Call Stack or not depending on if it’s empty or not.

    尽管仍在调用堆栈上运行并执行函数,但事件必须等待调用堆栈清空后才能运行。 Fluffykins准将让他们知道是否可以进入调用栈 ,这取决于是否为空。

让我们创建自定义事件! (Lets Create Custom Events!)

Event emitters are used extensively in Node.js libraries, so lets learn how to create our own and better understand how they work!

事件发射器在Node.js库中得到了广泛使用,因此让我们学习如何创建自己的事件发射器并更好地了解它们的工作原理!

All objects that emit events are instances of the EventEmitter class and all events inherit from the EventEmitter constructor. We’ll be creating two events for the bunnyError event emitter — bunnyWarning and bunnyNeed.

所有发出事件的对象都是EventEmitter 类的实例,并且所有事件都从EventEmitter构造函数继承。 我们将为bunnyError事件发射器创建两个事件-bunnyWarningbunnyNeed

Copy and paste this into a file called bunnyEmitter.js:

将其复制并粘贴到名为bunnyEmitter.js的文件中:

Alright so what’s happening here?

好吧,这是怎么回事?

First we require in Node.js’s EventEmitter object and then we create an instance of a new EventEmitter object that we will build custom events for. We call this instance bunnyError.

首先,我们需要在Node.js的EventEmitter对象中 ,然后创建一个新的EventEmitter对象的实例,以为其创建自定义事件。 我们将此实例称为bunnyError

Then we create an event listener for our first event, bunnyWarning, with the on method, which listens for the event. We handle this event when it’s used by triggering a callback that simply prints “BUNNY WARNING: warning.”

然后,使用on方法为第一个事件bunnyWarning创建一个事件侦听 ,该方法侦听该事件。 当使用此事件时,我们将通过触发仅显示“ BUNNY WARNING:警告”的回调来处理该事件。

Notice I used Template Literals — an ES6 feature. You can learn more them here. It’s the same as saying console.log(“BUNNY WARNING:” + message).

注意,我使用了模板文字 -ES6功能。 您可以在此处了解更多信息 。 就像说console.log(“ BUNNY WARNING:” + message)一样

Lastly we use the emit method to trigger or call the event. Once the event is called the callback should run. We can do this as many times as we want.

最后,我们使用emit方法触发或调用事件。 调用事件后,回调应运行。 我们可以根据需要多次执行此操作。

Assuming the file is on your Desktop, type node bunnyEmitter.js in your shell:

假设该文件在您的桌面上, 在您的shell中键入node bunnyEmitter.js

If you only want your event emitter to trigger one time, the EventEmitter object has a method called .once which you can use instead of .on:

如果只希望事件发射器触发一次,则EventEmitter对象具有一个名为.once的方法,您可以使用该方法代替.on:

yourEventEmitter.once(yourEvent, yourCallback)

With this, no matter how many times you emit yourEvent, it will only work one time.

这样,无论您发出yourEvent多少次,它都只能工作一次。

It’s good practice to limit the number of event listeners you have. In fact if you have more than ten, you will get a warning:

最好限制事件监听器的数量。 实际上,如果您有十个以上,则会收到警告:

"(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit."

So far you’ve seen terms such as events, event listener, and event handler being used. Lets make the main differences clear before we move on:

到目前为止,您已经看到诸如eventevent listenerevent handler之类的术语。 在继续之前,让我们先弄清楚主要区别:

The event listener is the event you create to listen for any incoming events. The event handler is the callback that will be triggered once the event listener hears the event.

事件监听器是你创建监听任何传入事件的事件事件处理程序事件监听器听到事件后将触发的回调。

In our custom event emitter example, the event listeners were bunnyWarning and bunnyNeeds and the event handlers were the callbacks of each event.

在我们的自定义事件发射器示例中, 事件侦听器bunnyWarningbunnyNeeds事件处理程序是每个事件的回调。

查看这些额外的资源 (Check out these extra resources)

Congrats! You’ve made it through Learn Node.js With Brigadier Fluffykins Part II! In today’s lesson you learned that Node.js is an event driven language and why this is useful for asynchronous behavior. You also learned how these events are processed via the Event Loop.

恭喜! 您已经通过Fluffykins准将 II 学习Learn Node.js了 ! 在今天的课程中,您了解了Node.js是事件驱动的语言,以及为什么它对异步行为很有用。 您还了解了如何通过事件循环处理这些事件。

We also took a dive into learning about the similarities between DOM events and events in Node.js to help you ease into this new realm a bit more.

我们还深入研究了DOM事件与Node.js中事件之间的相似性,以帮助您更轻松地进入这个新领域。

Lastly, we created out first EventEmitter and two awesome events!

最后,我们创建了第一个EventEmitter和两个很棒的事件!

Lets learn more about these topics as well as others we’ve only scratched in the next few lessons. Thank you for reading and stay tuned.

让我们更多地了解这些主题以及在接下来的几节课中仅涉及的其他主题。 感谢您的阅读和关注。

Keep your wisdom up to date by clicking the ❤ below and following, as more Learn Node.js With Brigadier Fluffykins is coming soon to Medium!

单击下面的❤,保持您的最新知识,更多信息了解Fluffykins与Brigadier Fluffykins即将发布!

Part I: Sync, Async, and Creating Your First Server!

第一部分:同步,异步和创建您的第一台服务器!

Part II: Events, EventEmitter & Event Loop

第二部分:事件,EventEmitter和事件循环

Part III: Request Object, Configure Routes, Serve Files

第三部分:请求对象,配置路由,服务文件

翻译自: https://www.freecodecamp.org/news/learn-node-js-with-brigadier-fluffykins-part-ii-events-eventemitter-the-event-loop-6d4c139694fb/

eventemitter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值