Home >Web Front-end >JS Tutorial >Understanding events and event loop in nodejs
Related recommendations: "nodejs Tutorial"
Friends who are familiar with javascript should have used events, such as mouse movement, mouse click, Keyboard input and so on. We listen to these events in javascript to trigger corresponding processing.
There are also events in nodejs, and there is also a special events module for specialized processing.
Simultaneous events and event loops are also very important concepts for building asynchronous IO in nodejs.
Today we will learn more about it.
nodejs provides a special module for events: lib/events.js.
Remember when we were talking about using nodejs to build a web server?
const server = http.createServer((req, res) => { res.statusCode = 200 res.setHeader('Content-Type', 'text/plain') res.end('welcome to www.flydean.com\n') })
Here, each request will trigger the request event.
The core API of nodejs is based on asynchronous event-driven architecture, so there are a lot of events in nodejs.
For example: net.Server will trigger an event every time there is a new connection, fs.ReadStream will trigger an event when a file is opened, and stream will trigger an event when the data is readable.
Let’s take a look at how to build a nodejs event:
const EventEmitter = require('events') const eventEmitter = new EventEmitter()
There are two commonly used methods for events, namely on and emit.
on is used to listen for events, and emit is used to trigger events.
eventEmitter.on('fire', () => { console.log('开火') }) eventEmitter.emit('fire')
emit can also take parameters. Let’s look at the next parameter:
eventEmitter.on('fire', who => { console.log(`开火 ${who}`) }) eventEmitter.emit('fire', '美帝')
Let’s look at the two parameters:
eventEmitter.on('fire', (who, when) => { console.log(`开火 ${who} ${when}`) }) eventEmitter.emit('fire', '川建国','now')
By default, EventEmitter starts with All listeners are called synchronously in the order they were registered. This ensures correct ordering of events and helps avoid race conditions and logic errors.
If asynchronous execution is required, you can use setImmediate() or process.nextTick() to switch to asynchronous execution mode.
eventEmitter.on('fire', (who, when) => { setImmediate(() => { console.log(`开火 ${who} ${when}`); }); }) eventEmitter.emit('fire', '川建国','now')
In addition, events also support several other methods:
once(): Add a single listener
removeListener() / off(): From Remove event listeners from events
removeAllListeners(): Remove all event listeners
We know that nodejs code runs in a single-threaded environment Yes, only one thing will be dealt with at a time.
This processing method avoids the problem of data synchronization in a multi-threaded environment and greatly improves processing efficiency.
The so-called event loop means that in a program cycle, after the processor has processed the events of this cycle, it will enter the next event cycle and process the events of the next event cycle. This is a cycle after cycle. .
If the processing of an event is blocked during event processing, it will affect the execution of other events, so we can see that in JS , almost all IO is non-blocking. This is also why there are so many callbacks in JavaScript.
Let’s look at a simple event loop example:
const action2 = () => console.log('action2') const action3 = () => console.log('action3') const action1 = () => { console.log('action1') action2() action3() } action1()
The above code output:
action1 action2 action3
We know that calls between functions are implemented through the stack. In the above example, our calling sequence is also implemented through the stack.
But not all methods in the function will be pushed onto the stack, and some methods will be put into the message queue.
Let’s give another example:
const action2 = () => console.log('action2') const action3 = () => console.log('action3') const action1 = () => { console.log('action1') setTimeout(action2, 0) action3() } action1()
The result of running the above code is:
action1 action3 action2
The result is different. This is because settimeout triggers the timer. When the timer expires, the callback function will be placed in the message queue to be processed instead of being placed on the stack.
The event loop will prioritize events in the stack. Only when there is no data in the stack will it switch to consuming events in the message queue.
Although the timeout time of setTimeout in the above example is 0, it still has to wait until action3 is executed before it can be executed.
Note that the timeout in setTimeout does not wait in the current thread. It is called by the browser or other JS execution environment.
Promise in ES6 introduces the concept of job queue. Using the job queue will execute the result of the asynchronous function as soon as possible instead of placing it at the end of the call stack.
For example:
const action2 = () => console.log('action2') const action3 = () => console.log('action3') const action1 = () => { console.log('action1') setTimeout(action2, 0) new Promise((resolve, reject) => resolve('应该在action3之后、action2之前') ).then(resolve => console.log(resolve)) action3() } action1()
Output result:
action1 action3 应该在action3之后、action2之前 action2
This is because the Promise resolved before the end of the current function will be executed immediately after the current function.
That is to say, the stack is executed first, then the job queue is executed, and finally the message queue is executed.
Let me first give you a definition called tick. A tick refers to an event cycle. Process.nextTick() refers to calling this function before the next event loop tick starts:
process.nextTick(() => { console.log('i am the next tick'); })
So nextTick must be faster than the setTimeout of the message queue.
nodejs provides a setImmediate method to execute code as quickly as possible.
setImmediate(() => { console.log('I am immediate!'); })
The function in setImmediate will be executed in the next iteration of the event loop.
The functions of setImmediate() and setTimeout(() => {}, 0) are basically similar. They will all be run on the next iteration of the event loop.
If you want to execute certain callback functions regularly, you need to use setInterval.
setInterval(() => { console.log('每隔2秒执行一次'); }, 2000)
要清除上面的定时任务,可以使用clearInterval:
const id = setInterval(() => { console.log('每隔2秒执行一次'); }, 2000) clearInterval(id)
注意,setInterval是每隔n毫秒启动一个函数,不管该函数是否执行完毕。
如果一个函数执行时间太长,就会导致下一个函数同时执行的情况,怎么解决这个问题呢?
我们可以考虑在回调函数内部再次调用setTimeout,这样形成递归的setTimeout调用:
const myFunction = () => { console.log('做完后,隔2s再次执行!'); setTimeout(myFunction, 2000) } setTimeout(myFunction, 2000)
更多编程相关知识,请访问:编程视频!!
The above is the detailed content of Understanding events and event loop in nodejs. For more information, please follow other related articles on the PHP Chinese website!