MIT Weblab笔记 - Asynchronous Control

Introduction

  • Synchronous: Happening consecutively, one after another.
  • Asynchronous: Multiple processes can run at the same time.

Node.js

Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code outside of a web browser.

  • Single-Threaded Event Loop: Unlike traditional multi-threaded servers that spawn a new thread for each client, Node.js uses a single-threaded event loop to manage all client connections. The Event Loop continuously checks the event queue to see if there are any events to be handled.
  • Non-blocking I/O: Node.js performs I/O operations (like reading from a database) asynchronously. Instead of waiting for the operation to complete, Node.js registers a callback and moves on to handle the next event. This non-blocking behavior ensures that Node.js can handle many I/O operations concurrently without getting bogged down by slow operations

Promises

Promise is an object that can exist in only one of three states.

  • Pending: The initial state. The operation is ongoing.
  • Fulfilled / Resolved: The operation completed successfully.
  • Rejected: The operation failed due to an error.

The state can only change from Pending to Fulfilled or from Pending to Rejected.

const myPromise = new Promise((resolve, reject) => {
    // This code runs immediately
    const success = true; 
    if (success) {
        resolve("Data"); // State becomes Fulfilled; "Data" is passed as the value
    } else {
        reject("Error"); // State becomes Rejected; "Error" is passed as the reason
    }
});

Even if the Promise resolves immediately, the code inside .then() will not run right away. It is placed into the Microtask Queue. It will execute only after the current synchronous script has finished, but before the next Event Loop cycle begins.

  • When you mark a function as async, JavaScript automatically wraps the return value in Promise.resolve().
  • The instance method .then() always returns a new Promise. This mechanism is what enables chaining.
  • Some APIs like fetch(), axios.get().

.then()

syntax

const myStories = get('/api/stories');
setStories(myStories);
  • the get() function returns a promise.
  • myStories is a promise object immediately after this line runs. The promise represents an operation that hasn’t completed yet. JavaScript continues executing subsequent code without waiting for the promise to resolve.
  • setstories is called immediately with the promise myStories, not with the actual data that the promise will resolve to.

Correct handling:

get('/api/stories').then((stories) => {
  setStories(stories);
}).catch((error) => {
    console.log(error.message);
});

.then((stories) => { ... }) sets up a handler that waits for the promise to resolve.

  • If promise fulfilled, execute .then() (the function insie .then() is put into the microtask queue).
  • If promise rejected, execute .catch() (the function insie .catch() is put into the microtask queue).

Async of promises

Promises let us keep running other code:

useEffect(() => {
  get('/api/stories').then((stories) => {
    setStories(stories);
  })
  console.log("do thing 1");
  console.log("do thing 2");
  console.log("do thing 3");
}, []);
  • These console.log statements execute synchronously, meaning they run immediately after the API request is initiated but before the promise resolves.
  • When the get function is called, it returns a promise and initiates the asynchronous operation to fetch data. JavaScript does not wait for this operation to complete. Instead, it continues executing the subsequent lines of code immediately. This is known as non-blocking behavior.

Handling multiple promises

const promise1 = get('/api/comments', { parent: parentId1 });
const promise2 = get('/api/comments', { parent: parentId2 });
const promise3 = get('/api/comments', { parent: parentId3 });
const promise4 = get('/api/comments', { parent: parentId4 });
const promise5 = get('/api/comments', { parent: parentId5 });

const promises = [promise1, promise2, promise3, promise4, promise5];

Promise.all(promises).then((allResults) => {
  // allResults represent a list with the result of each promise
}).catch((err) => {
  // Catch and report any error
});
  • Returns a promise that resolves to array of results of input promises
  • allResults represent a list with the result of each promise
Promise.race(promises).then((firstResult) => {
  // Do something with the first result
}).catch((err) => {
  // Catch and report any error
});
  • Return a single Promise
  • This returned promise settles as soon as any of the promises in the iterable (list in this example) settles (either fulfills or rejects).
Promise.any(promises).then((anyResult) => {
  // Do something with the first fullfilled promise
}).catch((err) => {
  // Catch and report any error
});
  • Return a sinfle Promise
  • This returned promise fulfills as soon as any of the promises in the iterable fulfills

await and async keywords

  • async function: declare a function to return a Promise.
  • Only asynchronous functions can use await. Asynchronous function is defined by async keyword. Asynchronous functions return control back to the caller before computation is done.
  • await waits for the promise to resolve and uses that value
const myFunction = async () => {
  console.log('Start');
  const data1 = await fetchData('url1');
  console.log('Data 1:', data1);
  const data2 = await fetchData('url2');
  console.log('Data 2:', data2);
  console.log('End');
}

myFunction();
console.log('After myFunction call');
  • When await is used, it pauses the execution of the async function until the awaited promise is resolved or rejected. This means that the lines of code following the await will not execute until the promise is settled. This “pause” is local to the async function where await is used.
  • While the async function is paused, the rest of the JavaScript (outside the specific function) code can continue to run, i.e., console.log('After myFunction call');. This means other tasks, events, and functions can continue to execute, keeping the overall program responsive.

MIT Weblab笔记 - Asynchronous Control
http://example.com/2024/07/15/MIT_Weblab/async-control/
Author
Songlin Zhao
Posted on
July 15, 2024
Licensed under