Asynchronous JavaScript

  • JS is single threaded --- i.e. two bits of script cannot run at the same time, they have to run one after another
  • usually JS runs code sequentially in top-down order --- but sometimes there is code that runs (or must run) after something else happens and also not sequentially --- this is asynchronous programming

Callbacks

  • we use callback functions to make sure a function won't run before a task is completed but will run right after it is completed
  • they are passed as parameters to other functions
  • can be named, anonymous, or an arrow function
    // named
    const message = function () {
      console.log('This message is shown after 3 seconds');
    }
    setTimeout(message, 3000);
    
    // anonymous
    setTimeout(function () {
      console.log('This message is shown after 3 seconds');
    }, 3000);
    
    // arrow
    setTimeout(() => {
      console.log('This message is shown after 3 seconds');
    }, 3000);
  • callbacks commonly used in event declarations --- e.g. a message that occurs when a button is clicked

Promises

  • "Quick recap: in Javascript, a Promise is an object used as a proxy for a value not yet known. It’s called a Promise because it’s saying “I may not know what the value of the return is right now, but I promise to return it at some point, stored inside this thing”. In that way , instead of immediately returning the final value (which a synchronous method would do ), Promises allow you to use an asynchronous method, get the final value, and queue up “next steps” that you want to run on the eventually-returned value,..." source
  • a promise is a special JavaScript object that links the 'producing code' and the 'consuming code' together
    • 'producing code' does something and takes time
    • 'consuming code' wants the result of the 'producing code' once it's ready
    • the 'producing code' takes whatever time it needs to produce the promised result, and the promise makes that result available to the 'consuming code' when it's ready
// constructor syntax
let promise = new Promise(function(resolve, reject) {
  // executor (the producing code)
});
  • the function passed to new Promise is called the executor --- when new Promise is created it runs automatically --- it contains the producing code which should eventually produce the result
  • the resolve and reject are callbacks provided by JS --- our only code is within the executor
  • the promise object returned by the new Promise constructor has these internal properties:
    • state: initially 'pending', then changes to either 'fulfilled' when resolve is called or 'rejected' when reject is called
    • result: initially undefined, then changes to value when resolve(value) is called or error when reject(error) is called

So the executor eventually moves the promise to one of these states:

Diagram of the Promise Process

  • example of 'fulfilled promise':
    let promise = new Promise(function (resolve, reject) {
      // after 1 second, signal that the job is done with the result 'done'
      setTimeout(() => resolve('done'), 1000);
    });
  • example of 'rejected promise':
    let promise = new Promise(function (resolve, reject) {
      // after 1 second, signal that the job is done with the result 'done'
      setTimeout(() => reject(new Error ('Whoops!')), 1000);
    });
  • a promise that is either resolved or rejected is called 'settled' (as opposed to the initial state of 'pending')
  • the executor should call only one --- resolve or reject --- any state change is final (immutable) --- all further calls of resolve and reject are ignored
  • resolve/reject expect only one argument (or none) and will ignore any additional arguments
  • usually an executor does something asynchronously and calls resolve/reject after some time --- but we can call them immediately
  • the properties state and result of the Promise are internal --- they can't be directly accessed --- we can use .then, .catch, and .finally for that

Consumers: then, catch, and finally

then

  • the first argument of .then is a function that runs when the promise is resolved, and receives the result
  • the second argument is a function that runs when the promise is rejected, and receives the error
  • syntax:
    promise.then(
      function(result) { /* handle a successful result */ },
      function(error) { /* handle an error*/ }
    );

catch

  • if the promise is rejected, the return value passes through and .thens and is picked up by the catch

Copyright © 2022