Asynchronous Behavior

Part 2

Review

By default, JavaScript has a synchronous and single threaded execution model

Review

Changes to the DOM or style will not be rendered until JavaScript execution halts

const bar = document.querySelector('#bar');

for(let i = 0; i < 100; i += 1){
    bar.style.width = `${i}%`;
}

Review

For certain events, or functions, JavaScript can execute code asynchronously

  • Network Requests
    • (fetch)
  • User Input
    • (keypress, mouse press)
  • Timers
    • (setInterval, setTimeout)
  • WebWorkers

Two methods

of accomplishing asynchronous behavior

Callbacks

Promises

Callbacks

A callback is a function passed to another function as a parameter

 

The function can be executed (called) when some work or event is complete 

const DoSomethingWithPi = callback => {

    const pi = reallyLongFunction();

    callback(pi)
};

const DoubleAndLog = data => console.log(data*2);

DoSomethingWithPi(DoubleAndLog); 

//6.2831853072

Callback Example

(Named function)

const DoSomethingWithPi = callback => {

    const pi = reallyLongFunction();

    callback(pi)
};


DoSomethingWithPi(data => console.log(data*2)); 

//6.2831853072

Inline callback

(Anonymous Function)

codepen example

 

demo basic callback, event binding, timer

//Event Listener

const name = document.querySelector('#name');

name.addEventListener('keydown', event => {
    console.log(event.keycode);
});


//setTimeout

window.setTimeout(()=>{
    alert('5 seconds went by!')
}, 5000);

Document and Window functions implement USING callback pattern

const img = document.querySelector('#img');

const showPopup = () => {
    //show a popup window

    document.addEventListener('click', hidePopup);
};

const hidePopup = () => {
    //hide the popup window
    document.removeEventListener('click', hidePopup);
};

img.addEventListener('click', showPopup);


Benefits of NAMED callbacks

Multiple Async Processes

A user clicks 'login,' which triggers a network request to the login service. This returns a session, which now requests the users personalized content. The content is sent to a render function.

Multiple Async Processes

userButtonClick(
    LoginService(
        GetPersonalizedData(
            RenderContent(){
                //do work here
            })
        })
    })
});

Callback Hell

fs.readdir(source, function (err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
              if (err) console.log('Error writing file: ' + err)
            })
          }.bind(this))
        }
      })
    })
  }
})

When your code starts to resemble a pyramid, you're in callback hell.

Promises

What is a promise?

A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

What does a promise look like?

const dice = new Promise( ... );

dice.then(  res => {})
    .then(  res => {})
    .catch( res => {});

Look familiar?

const dice = new Promise( ... );

dice.then(  res => {})
    .then(  res => {})
    .catch( res => {});
fetch('http://www.domain.com/api/v1/service')
    .then(  res => {})
    .then(  res => {})
    .catch( err => {});

Just like addEventListener is implemented using a callback, fetch is implemented using a promise

Interior of a Promise

A new promise takes a function (which does something asynchronous). This function has two parameters: resolve and reject.

 

Resolve triggers the first "then"

 

Reject triggers the "catch"

Promise Example

const RiggedDice = new Promise((resolve, reject) => {
    const roll = Math.floor(Math.random() * 5) + 1;

    if(roll >= 5){
        resolve(roll);
    } else {
        reject(roll);
    }
});

RiggedDice
    .then(roll => console.log(`Yay! you rolled a ${roll}`)
    .catch(roll => console.log(`Bummer! you rolled a ${roll}`);

codepen example

Promise based image loader

Made with Slides.com