Async Foundataions

Callback Function

  • What is a callback function?
    • A callback function is a function that is passed into another function as a parameter then invoked by that other function

IMAGE ALT TEXT HERE

  • What is a higher order function?

    • A higher order function is a function that accept a callback as a parameter
  • What are callbacks used for?

    • Advanced Array Methods
    • Browser events
    • AJAX Requests
    • React Development

Example: Duplicate Code without Callbacks

In [22]:
function sendMessageConsole(message) {
  console.log(message);
}

function sendMessageAlert(message) {
  // alert(message);
}

function sendMessageConfirm(message) {
  return confirm(message);
}

sendMessageAlert("Lots of duplication");

Example: Refactor With Callbacks

In [23]:
// Make sendMessage a higher order function and return a callback function
function sendMessage(message, callback) {
  return callback(message);
}

sendMessage("Message for console", console.log);
// sendMessage("Message for alert", alert);
// var answer = sendMessage("Are you sure??", confirm);
Message for console

Example: Callbacks with Function Declarations

In [24]:
//higher order function: greet, callback function: formatter
function greet(name, formatter) {
  return "Hello, " + formatter(name);
}

function upperCaseName(name) {
  return name.toUpperCase();
}

greet("Tim", upperCaseName); //Hello, TIM
Out[24]:
'Hello, TIM'

Example: Callbacks with Anonymous Function (more common)

In [25]:
function greet(name, formatter) {
  return "Hello, " + formatter(name);
}

greet("Tim", function(name) {
  return name.toUpperCase();
});

greet("Tim", function(name) {
  return name + "!!!!!";
})
Out[25]:
'Hello, Tim!!!!!'

forEach Function

  • forEach will invoke callback with 3 parameters everty time

Example: Callback signature

function callback(curElement, curIndex, array){
    //call implemented by caller of function
}

Example: Implemention of forEach

In [26]:
function myForEach(arr, callback){
  for (var i=0;i<arr.length;i++){
      callback(arr[i],i,arr);
  }
}

findIndex Function

In [27]:
function findIndex(arr, callback){
  for (var i=0;i<arr.length;i++){
    if (callback(arr[i],i,arr)){
      return i;
    }
  }
  return -1;
}

Common mistake with callback

  • callback has nothing to return and null returns false
var langs = ["Java", "C++", "Javascript"];
findIndex(langs, function(lang, index, arr){
        lang === "Javascript";  //missing return keyword
});

What is the Stack?

  • An ordered data structure
  • Keeps track of function invocations
  • Part of the JavaScript runtime (you don't access it directly)

How Your Code Changes the Stack?

  • Whenever you invoke a function, the details of the invocation are saved to the top of the stack (pushed to the top)
  • Whenever a function returns, the information about the invocation is taken off the top of the stack (popped off of the top)

Stack Frame Contents

  • The function that was invoked
  • The parameters that were passed to the function
  • Current line number

Stack Definition

  • An ordered set of stack frames
  • Most recently invoked function is on the top of the stack
  • The bottom of the stack is the first function invoked
  • The stack is processed from top to bottom

Heap Definition

-An area in memory where the your data is stored

In [28]:
// The object is created in the heap. obj is a reference to the object.
var obj = {firstName: "Tim", lastName: "Garcia"};
In [29]:
// New data is not created, only a copy of the reference
var referenceCopy = obj;

setTimeout and setInterval

setTimeout

  • A function that asynchronously invokes a callback after a delay in milliseconds

setInterval

  • A function that continually invokes a callback after every X milliseconds, where X is provided to setInterval

Example: setTimeout usage

function callback() {
  console.log("callback function");
}
var delay = 1000;  // Delay is in ms
setTimeout(callback, delay);

Example: Canceling setTimeout

//Output Console: Canceling the first setTimeout 42
var timerId = setTimeout(function() {
  console.log("This function runs in 30 seconds");
}, 30000);

setTimeout(function() {
  console.log("Canceling the first setTimeout", timerId);
  clearTimeout(timerId);
}, 2000);

Example: setInterval usage

function callback() {
  console.log("callback is called continuously");
}
var repeat = 3000;
setInterval(callback, repeat);

Example: Canceling setInterval

var num = 0;
var intervalId = setInterval(function() {
  num++;
  console.log("num:", num);
  if (num === 3) {
    clearInterval(intervalId);
  }
}, 1000);

Event Loop and the Queue

  • The Queue

    • An ordered list of functions waiting to be placed on the stack
    • Functions in the queue are processed on a first in, first out basis (FIFO)
  • The Event Loop

    • Queue ---> Stack
    • Functionality in the JavaScript runtime that checks the queue when the stack is empty
    • If the stack is empty, the front of the queue is placed in the stack
  • Queue Example:

    • Waiting for the Stack to Empty
    • The callback function even though we set a setTimeout of 0 did not actually get invoked until after the stack is empty and until after the event loop had taken off the queue and place it on the stack
  • JavaScript is Single Threaded

    • Single Threaded: Code execution is linear. Code that is running cannot be interrupted by something else going on in the program.

Example:

In [30]:
function square(n) {
  return n * n;
}

setTimeout(function() {
  console.log("Callback is placed on the queue");
}, 0);

console.log(square(2));
4

Promise Basics

  • What is a Promise?
    • Conceptually a promise is an object that represents a task that will be completed in the future
  • Analogy:
    • Taking an number at a government office before you can get helped. The piece of paper you get is like your promise. The help you get at the counter is like the invocation of your callback.
  • .then will be invoked if success/resolve
  • .catch will be invoked if fail/reject

Example: Promise: With Randomly Occurring Errors

In [31]:
var p1 = new Promise(function(resolve, reject) {
  var num = Math.random();
  if (num < 0.5) {
    resolve(num);
  } else {
    reject(num);
  }
});

p1.then(function(result) {
  console.log("Success:", result);
}).catch(function(error) {
  console.log("Error:", error);
});
Callback is placed on the queue
Success: 0.2866011906726085

Example: Wrap setTimeout With Promise

Asynchronous Code: obj promise will be created before setTimeout is finished

In [32]:
var promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    var randomInt = Math.floor(Math.random() * 10);
    resolve(randomInt);
  }, 4000);
});

promise.then(function(data) {
  console.log("Random int passed to resolve:", data);
});
Random int passed to resolve: 5

Promise Chaining

  • Promises In Practice

    • It is useful to understand how promises work (resolve, reject), but in practice you will often use promises that are returned to you
  • Nested Callbacks

    • Disadvantages of Nested Callbacks
    • The code is hard to read
    • Logic is difficult to reason about
    • The code is not modular

Example: Nested Async Callbacks (to be refactored)

var counter = 0;
setTimeout(function() {
  counter++;
  console.log("Counter:", counter);
  setTimeout(function() {
    counter++;
    console.log("Counter:", counter);
    setTimeout(function() {
      counter++;
      console.log("Counter:", counter);
    }, 3000);
  }, 2000);
}, 1000);

Example: Refactor

Step 1: Create a Function Declaration

In [33]:
var counter = 0;
function incCounter() {
  counter++;
  console.log("Counter:", counter);
}

Step 2: Create a runLater Function

In [34]:
function runLater(callback, timeInMs) {
  var p = new Promise(function(resolve, reject) {
    setTimeout(function() {
      var res = callback();
      resolve(res);
    }, timeInMs);
  });
  return p;
}

Step 3: Chain Promises

In [35]:
runLater(incCounter, 1000).then(function() {
  return runLater(incCounter, 2000);
}).then(function() {
  return runLater(incCounter, 3000);
}).then(function() {
  // final .then not necessary
});
Counter: 1
Counter: 2
Counter: 3