Programming Models: Sequential, Concurrent, and Parallel
Sequential Programming
- Sequential programming is the traditional approach where tasks are executed one after another.
 - Each task must complete before the next one begins.
 - It's simple to understand but can be inefficient when dealing with multiple operations.
 
function task1() {
  // Task 1 execution
}
function task2() {
  // Task 2 execution
}
task1();
task2(); // Task 2 starts only after Task 1 finishes
							Characteristics of Sequential Programming
- Single task at a time.
 - Blocking: One operation must complete before the next one starts.
 - Example: Reading a file and processing its content one after another.
 
Concurrent Programming
- Concurrent programming refers to executing multiple tasks in overlapping time periods.
 - Tasks don't necessarily execute at the same time, but their progress is interleaved.
 
function task1() {
  // Task 1 execution
}
function task2() {
  // Task 2 execution
}
setTimeout(task1, 1000);  // Task 1 is delayed
task2();                 // Task 2 can run before Task 1 completes
							Characteristics of Concurrent Programming
- Interleaving tasks: Multiple tasks make progress within the same time frame.
 - Non-blocking: Tasks may yield control during their execution.
 - Example: A web server handling multiple user requests.
 
Parallel Programming
- Parallel programming is when multiple tasks run at exactly the same time on multiple processors or cores.
 - It is a subset of concurrent programming where tasks are truly simultaneous.
 
// Parallel execution with multiple threads
parallelize(task1, task2);
							Characteristics of Parallel Programming
- Simultaneous execution: Tasks are executed at the same time.
 - Requires multiple processors/cores.
 - Example: Image processing where different parts of an image are processed simultaneously.
 
Comparing the Three Models
- Sequential: One task at a time, linear execution.
 - Concurrent: Multiple tasks progress within the same time period.
 - Parallel: Multiple tasks execute at the same time on separate processors.
 
Example: Cooking Analogy
- Sequential: Cook one dish at a time, finishing one before starting another.
 - Concurrent: Start cooking one dish while another is simmering.
 - Parallel: Two chefs cooking two dishes at the same time on separate stoves.
 
Conclusion
- Sequential, concurrent, and parallel programming address different needs.
 - Choosing the right model depends on the problem and hardware capabilities.
 
Introduction to Promises in JavaScript
What is a Promise?
A Promise in JavaScript is an object that represents the eventual completion (or failure) of an asynchronous operation.
const promise = new Promise((resolve, reject) => {
  // asynchronous operation
});
							States of a Promise
Promises have three states:
- Pending: Initial state, neither fulfilled nor rejected.
 - Fulfilled: The operation completed successfully.
 - Rejected: The operation failed.
 
let promise = new Promise((resolve, reject) => {
  // initially pending
});
							Example of Promise Resolution
The resolve() function signals the success of the asynchronous operation.
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Success!"), 1000);
});
promise.then(result => console.log(result)); // "Success!" after 1 second
							Example of Promise Rejection
The reject() function is used to signal failure in the operation.
const promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("Failure!")), 1000);
});
promise.catch(error => console.error(error)); // Error: Failure!
							Promise Methods: then, catch, finally
							- 
then(): Used to handle the success case. - 
catch(): Used to handle errors or rejection. - 
finally(): Runs regardless of the outcome. 
promise
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => console.log("Operation complete"));
							Chaining Promises
Promises can be chained to handle sequences of asynchronous operations.
fetchData()
  .then(data => processData(data))
  .then(result => displayResult(result))
  .catch(error => handleError(error));
							Async/Await: Modern Approach
async/await simplifies working with promises by allowing you to write asynchronous code that looks synchronous.
async function fetchData() {
  try {
    let data = await fetch('https://api.example.com/data');
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}
							What is Async/Await?
- Async/Await is a syntactic sugar built on top of Promises, introduced in ECMAScript 2017 (ES8).
 - It allows you to write asynchronous code that reads and behaves like synchronous code.
 - Makes code more readable and easier to maintain, especially for complex chains of Promises.
 
async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  console.log(data);
}
							How async Works
							- When a function is declared as 
async, it automatically returns a Promise. - The 
asynckeyword allows the use of theawaitkeyword within that function. 
async function myAsyncFunction() {
  return "Hello, Async!";
}
myAsyncFunction().then(result => console.log(result)); // "Hello, Async!"
							- Without 
async, the above function would just return a regular value, not a Promise. 
How await Works
							- The 
awaitkeyword is used insideasyncfunctions to pause the execution of the function until the Promise is resolved. - It makes asynchronous code behave as if it were synchronous, without blocking the main thread.
 
async function fetchData() {
  let response = await fetch('https://api.example.com/data'); 
  let data = await response.json(); 
  console.log(data); 
}
							Key Characteristics of await
							- 
Pauses execution: 
awaitpauses the function execution until the promise is settled (either resolved or rejected). - 
Non-blocking: Even though 
awaitpauses the async function, it does not block the execution of other code outside the function. 
async function demo() {
  console.log("Start");
  let result = await someAsyncTask();
  console.log(result);
}
console.log("Code after async call");  // This will run immediately
							Handling Errors with Async/Await
- Instead of using 
.catch()to handle errors in Promises,async/awaitallows you to handle errors with try-catch blocks. 
async function fetchData() {
  try {
    let response = await fetch('https://api.invalid-url.com');
    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("An error occurred:", error);
  }
}
							Parallelism with Async/Await
- Multiple awaits in a function will run sequentially by default. However, you can execute Promises in parallel by calling them first and then awaiting their resolution.
 
async function loadData() {
  let promise1 = fetch('https://api.example.com/data1');
  let promise2 = fetch('https://api.example.com/data2');
  
  let [data1, data2] = await Promise.all([promise1, promise2]);
  console.log(data1, data2);
}
							Using Promise.all() with Async/Await
							- 
Promise.all()allows you to run multiple asynchronous tasks in parallel and wait for all of them to complete. - This is useful when you have independent asynchronous operations that can be executed simultaneously.
 
async function getData() {
  let [result1, result2] = await Promise.all([
    fetch('https://api.example.com/data1'),
    fetch('https://api.example.com/data2')
  ]);
  console.log(result1, result2);
}
							Benefits of Async/Await
- Simplicity: Makes code more readable and easier to maintain compared to Promise chains.
 - 
Error handling: Uses 
try-catch, making error management more straightforward. - Non-blocking: Code execution continues normally without being blocked by async operations.
 
Async/Await vs Promises
- 
Promises: Use 
.then()and.catch()for handling asynchronous operations. - 
Async/Await: Allows asynchronous code to be written in a synchronous style using 
awaitandtry-catchfor error handling. 
| Feature | Promises | Async/Await | 
|---|---|---|
| Syntax | More verbose | Cleaner, more readable | 
| Error Handling | .catch() | 
try-catch | 
| Execution Style | Chain-based | Synchronous-looking | 
| Performance | Can be parallelized | Can use Promise.all() for parallelism | 
Conclusion
- Async/Await simplifies asynchronous programming by making it more readable.
 - It builds on top of Promises and is great for writing cleaner, more maintainable code.
 - Always consider combining it with 
Promise.all()for parallelism when needed. 
Conclusion
- Promises help manage asynchronous code in a cleaner and more readable way.
 - Methods like 
then(),catch(), andfinally()offer flexibility. - Async/await provides a simpler syntax for working with promises.
 
Programming Models: Sequential, Concurrent, and Parallel
By Néstor Aldana
Programming Models: Sequential, Concurrent, and Parallel
- 158