The Event demultiplexer is a notification-issuing interface within the Node JS. It is used to gather every request from watched sources in form of an event and queues each event in a queue. It is the demultiplexer that forms the Event Queue. Event demultiplexer is an API run by Libuv.

All the collected requests are distributed in those different event queues. The queue at the top takes highest priority, and the queue at the bottom takes the least.
So, event loop checks timers queue first and if there are events that are ready to be passed to call stack with its callback to be executed, event loop will handle it. After event loop is done with timers queues, however before jumping to next queue, event loop will look at 2 other queues that run by node itself, and will handle those queues first. those are:
Next Ticks Queue — Callbacks added using process.nextTick function
Other Microtasks Queue — Includes other microtasks such as resolved promise callbacks, console.log etc.
After event loop is done with those 2 queues, then it will move to next queue which is I/O callbacks.
Note that Node event loop is single threaded. However for computationally intensive or time consuming tasks libuv has thread pool which by default has 4 pools, not to block the event loop. There are only four things that use this thread pool - DNS lookup, fs, crypto and zlib. Everything else executes in the main thread irrespective or blocking or non blocking.
So far we had event loop which handles events in event queues and thread pool that run by libuv for some other functions. Node standard library also has some functions that make use of code that is built into the underlying operating system through libuv. All modern operating systems provide APIs to interact with libuv.
Libuv delegates some tasks like network I/O and fs module's functions to operating system, so OS runs those tasks and brings the results to Libuv.