Node.js is a JavaScript runtime environment that allows JavaScript code execution on the server side. It allows non-blocking, event-driven, and highly scalable applications, vastly used for building real-time applications. Node.js offers various execution models with practical usage. Node.js supports non-blocking operations, which means asynchronous programming, allowing several operations to be carried out simultaneously without blocking the other operations.
In this example, we’ll talk about the difference between two execution models of JavaScript: parallel and sequential execution.
This type of execution has a queue of operations to be carried out one after another. One task has to be completed without moving on to the next task. The event loop processes only one task at a time, ensuring the second operation doesn't begin until the current task finishes. Sequential execution plays an important role in executing those functions where the order of execution matters in the overall execution.
The execution can have a blocking nature, especially for tasks requiring high processing time like I/O operations, database queries, and network requests. The blocking nature causes the event loop to pause, causing delayed responsiveness.
The possible use cases of sequential execution are synchronous coding problems where each task depends on the completion of the previous task and problems where dependencies exist between tasks.
Here’s a coding example to demonstrate the sequential execution of tasks.
//Sequential execution example // Function to print status of task 1 after timeout function task1(i) { setTimeout(() => { console.log("Executing task ",{i}); i = i + 1; // call the next sequential task 2 task2(i); },1000); } // Function to print status of task 2 after timeout function task2(i) { setTimeout(() => { console.log("Executing task ",{i}); i = i + 1; // call the next sequential task 3 task3(i) },1000); } // Function to print status of task 3 after timeout function task3(i) { setTimeout(() => { console.log("Executing task ",{i}); i = i + 1; },1000); } //sequentially calling task 1 console.log("Sequential Execution: "); task1(1);
In the code:
Lines 3,13,23: Define function task1
, task2
, and task3
with an iterator i
that indicates the tasks under execution.
Lines 4,14, 24: Definition of time-delayed task using setTimeout
.
Lines 5, 15, 25: Logging of execution of the task and its value, i.e., i
.
Line 6, 16, 26: Incrementation of variable i
that represents the task under execution.
Line 8: Initiation of task2
with i
value 2.
Line 18: Initiation of task3
with i
value 3.
Line 32: Initiation of task1
with i
value 1.
While sequential execution seems simple and deterministic in task handling, it may lead to performance bottlenecks in the case of long-running operations.
Parallel execution makes use of the cores and processors. Parallel execution divides tasks into multiple portions and executes each of them simultaneously on different processors. This type of execution helps avoid bottlenecks created in sequential execution.
In parallel execution, tasks are carried out concurrently and do not depend on or wait for other tasks. Each task executes independently, and the events loop is available to be used by other tasks. No task blocks the execution of other tasks. This type of execution is particularly beneficial in executing applications with CPU-bound tasks. The tasks can be high data processing or solving complex mathematical problems.
Parallel execution is beneficial in performing asynchronous operations, parallelizing tasks and in applications where server executes multiple tasks simultaneously.
Here’s a coding example to demonstrate the parallel execution of tasks. It makes use of the Promise
to parallelize tasks.
// Parallel Execution Example // Function to print Task 1 status after timeout function task1(i) { return new Promise((resolve) => { setTimeout(() => { console.log("Task",{i} ,"completed"); resolve(); }, 1000); }); } // Function to print Task 2 status after timeout function task2(i) { return new Promise((resolve) => { setTimeout(() => { console.log("Task",{i} ,"completed"); resolve(); }, 1000); }); } // Function to print Task 3 status after timeout function task3(i) { return new Promise((resolve) => { setTimeout(() => { console.log("Task",{i} ,"completed"); resolve(); }, 1000); }); } console.log("\nParallel Execution:"); // Asynchronous function to execute tasks in parallel async function executeParallelTasks() { // Wait for all tasks to be complete await Promise.all([task1(1), task2(2), task3(3)]); console.log("Parallel execution complete"); } executeParallelTasks();
In the code:
Lines 3,13,23: Define function task1
, task2
, and task3
with i
indicating the tasks under execution. i
don’t indicate iteration, as all tasks are executing concurrently.
Lines 4,14,24: Initiate Promise
function. The Promise
function helps create an asynchronous operation by assigning a value to the Promise
at the end of function's execution.
Lines 5,15,25: Definition of time-delayed task using setTimeout
.
Lines 6,16, 26: Logging of execution of the task and its value, i.e., i
.
Lines 7,17,27: resolve
function called indicating completion of the Promise
function.
Line 34: Initiation of asynchronous function using async
Line 36: await
waits for Promise.all
to return the Promise
of all the parallel tasks.
Line 40: Initiation of the parallel processes.
Parallel execution makes the processing time smaller and manages the tasks efficiently.
Let’s conclude the key differences between sequential and parallel execution of tasks. It is important to note that while each execution type has its specific practical usage, misusing the execution can hinder the performance of the operations. Here is a conclusive table to differentiate between the two.
Properties | Sequential execution | Parallel execution |
Sync vs. async | Synchronous | Asynchronous |
Execution order | In queue | Simultaneous |
Blocking vs. non-blocking | Blocking | Non-blocking |
Performance in CPU-bound operations | Slower | Faster |
Different type of operation needs a different type of execution. Identifying the type of operation can help with the efficiency in which the operation can be carried out.
Free Resources