YouTip LogoYouTip

Nodejs Event Loop

The event loop is the core mechanism for Node.js to handle non-blocking I/O operations, enabling a single thread to efficiently process multiple concurrent requests.\n\nNode.js is a single-threaded JavaScript runtime that utilizes the event loop to handle asynchronous operations, such as file reading, network requests, and database queries.\n\nThe event loop enables Node.js to perform non-blocking code execution, handle multiple connections, and execute asynchronous I/O operations.\n\nThe event loop allows Node.js to handle a massive amount of concurrent I/O operations without causing thread blocking, which is the key to Node.js efficiently processing concurrent requests.\n\n!(#)\n\n### Phases of the Event Loop\n\nThe event loop is divided into multiple phases, each handling specific tasks. The key phases are as follows:\n\n* **Timers**: Executes callbacks for `setTimeout()` and `setInterval()`.\n* **I/O Callbacks**: Handles some deferred I/O callbacks.\n* **Idle, prepare**: Used internally, not commonly seen.\n* **Poll**: Retrieves new I/O events and executes I/O-related callbacks.\n* **Check**: Executes `setImmediate()` callbacks.\n* **Close Callbacks**: Handles close callbacks, such as `socket.on('close', ...)`.\n\n### Flow of the Event Loop\n\n* **Tasks enter the event loop queue**.\n* The event loop processes tasks in the order of its phases, and each phase has its own callback queue.\n* The event loop will wait for new events to arrive during the `poll` phase; if there are no events, it will check the callbacks of other phases.\n* If both `setImmediate()` and `setTimeout()` are present, `setImmediate()` executes first in the `check` phase, while `setTimeout()` executes in the `timers` phase.\n\n## Example\n\nsetTimeout(()=>{\n\n console.log('Timeout callback');\n\n},0);\n\nsetImmediate(()=>{\n\n console.log('Immediate callback');\n\n});\n\nconsole.log('Main thread execution');\n\nOutput order:\n\n* `Main thread execution` is printed first.\n* The execution order of `setImmediate()` and `setTimeout()` depends on the state of the current event loop, but generally, `setImmediate()` will execute first.\n\n### Macrotasks and Microtasks\n\n* **Macrotasks**: `setTimeout`, `setInterval`, `setImmediate`, I/O operations, etc.\n* **Microtasks**: `process.nextTick`, `Promise.then`.\n\n**Execution order:** Microtasks have a higher priority than macrotasks and will execute immediately after the callbacks of the current phase finish.\n\n## Example\n\nsetTimeout(()=>{\n\n console.log('Timeout callback');\n\n},0);\n\nPromise.resolve().then(()=>{\n\n console.log('Promise callback');\n\n});\n\nconsole.log('Main thread execution');\n\nExecution output result:\n\nMain thread execution Promise callback Timeout callback\n### process.nextTick()\n\nprocess.nextTick() will execute the microtask after the current operation ends and before the next phase begins. Its priority is higher than that of Promises.\n\n## Example\n\nprocess.nextTick(()=>{\n\n console.log('Next tick callback');\n\n});\n\nconsole.log('Main thread execution');\n\nOutput:\n\nMain thread execution Next tick callback\n\n* * *\n\n## Event-Driven Programs\n\nIn Node.js, event-driven programming is primarily implemented through the EventEmitter class.\n\nEventEmitter is a built-in class located in the events module. By inheriting from EventEmitter, you can create your own event emitters, and register and trigger events.\n\nThrough this mechanism, Node.js can efficiently handle asynchronous tasks, achieving concurrent processing even in a single-threaded environment.\n\n!(#)\n\nThis is how the entire event-driven process is implemented, which is very concise. It is somewhat similar to the Observer pattern, where an event is equivalent to a Subject, and all handler functions registered to this event are equivalent to Observers.\n\n**Basic Concepts:**\n\n* **Event**: An action or state change that occurs in a program, such as a file read completion or an HTTP request arrival.\n* **Event Emitter**: `EventEmitter` is a built-in Node.js module used to emit and listen to events.\n* **Event Handler**: A callback function associated with an event, which is called when the event occurs.\n\n**Event-Driven Flow:**\n\n* **Register Event**: Register events and their corresponding handlers through an `EventEmitter` instance in the program.\n* **Trigger Event**: When a specified event occurs, `EventEmitter` will trigger that event.\n* **Handle Event**: The event loop will schedule the corresponding callback function to execute the task.\n\nNode.js has multiple built-in events. We can bind and listen to events by importing the events module and instantiating the EventEmitter class, as shown in the following example:\n\n// Import events module var events = require('events');// Create eventEmitter object var eventEmitter = new events.EventEmitter();\nThe following program binds an event handler:\n\n// Bind event and event handler eventEmitter.on('eventName', eventHandler);\nWe can trigger events through the program:\n\n// Trigger event eventEmitter.emit('eventName');\n### Example\n\nCreate a hello.js file with the following code:\n\n## Example 1\n\nconst EventEmitter = require('events');\n\nconst myEmitter =new EventEmitter();\n\n// Register event handler\n\n myEmitter.on('greet',()=>{\n\n console.log('Hello, world!');\n\n});\n\n// Trigger event\n\n myEmitter.emit('greet');\n\nOutput:\n\nHello, world!\nCreate a main.js file with the following code:\n\n## Example 2\n\nvar events = require('events'); var eventEmitter = new events.EventEmitter(); var connectHandler = function connected(){console.log('Connection successful.'); eventEmitter.emit('data_received'); }eventEmitter.on('connection', connectHandler); eventEmitter.on('data_received', function(){console.log('Data received successfully.'); }); eventEmitter.emit('connection'); console.log("Program execution completed。");\n\nNext, let's execute the above code:\n\n$ node main.js Connection successful.Data received successfully.Program execution completed。\n\n* * *\n\n## How do Node Applications Work?\n\nIn Node applications, functions that perform asynchronous operations take a callback function as their last argument, and the callback function receives an error object as its first argument.\n\nNext, let's revisit the previous example. Create an input.txt file with the following content:\n\nOfficial website address: example.com\nCreate a main.js file with the following code:\n\nvar fs = require("fs"); fs.readFile('input.txt', function (err, data) { if (err){ console.log(err.stack); return; } console.log(data.toString());}); console.log("Program execution completed");\nIn the above program, fs.readFile() is an asynchronous function used to read a file. If an error occurs during the file reading process, the error err object will output the error message.\n\nIf no error occurs, readFile skips the output of the err object, and the file content is output via the callback function.\n\nExecute the above code, and the execution result is as follows:\n\nProgram execution completedOfficial website address: example.com\nNext, let's delete the input.txt file, and the execution result is as follows:\n\nProgram execution completedError: ENOENT, open 'input.txt'\nBecause the file input.txt does not exist, an error message is output.
← Nodejs BufferNodejs Repl β†’