Truly Grasping Async and Concurrency In JavaScript

const me = {
  name: "Martin McKeaveney",
  company: "SquareFoot",
  twitter: "@mmckeaveney94",
  github: "mmckeaveney"
}

👋

asynchronous

adjective UK  /eɪˈsɪŋ.krə.nəs/ US  /eɪˈsɪŋ.krə.nəs/

 not happening or done at the same time or speed

🍔

Learning Curve

Browser APIs 👨‍💻

Callbacks 📲

A function that calls back when the asynchronous task is complete.

Versatile 🔧

 

Performant 🏎️

 

Fairly easy to grasp conceptually

fs.readFile('data.json', 'utf8', (err, jsonString) => {
    if (err) {
        console.error('File read failed:', err);
        return;
    }
    console.log('Me Second!', jsonString);
});

console.log('Me First!')

Callbacks 📲

Callback Queue

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))
        }
      })
    })
  }
})

📲👿🔥

Promises 🙏

A reference to a future value.

Thin but powerful abstraction around callbacks 💪

 

Chainable 🔗

 

Error Handling ⚠️

 

Composable 🎼

Promises 🙏

function display(data) {
  console.log(data);
}

// { value: undefined, onFulfilled: [] }
const futureData = fetch('http://some/url');

// { value: undefined, onFulfilled: [display] }
futureData.then(display);

console.log('Me First!');
// { value: 'data from server', onFulfilled: [display] }

Microtask Queue vs Callback Queue 

function display(data) { console.log(data); }
function printHello() { console.log('Hello'); }
function blockFor300ms() { /* block JS thread for 300 ms */}

setTimeout(printHello, 0);

const futureData = fetch('http://foobar');
futureData.then(display);

blockFor300ms();

console.log('Me First');
Me First!
Data from server!
Hello!

What is wrong with this?

🤔

 

Generators ⏸️

function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = numberGenerator();
generator.next(); // { value: 1, done: false } 
generator.next(); // { value: 2, done: false }
generator.next(); // { value: 3, done: true }

"Pausable Functions"

Async Generators ⏸️

function doWhenDataReceived (value) {
 // response from promise - 'hi from server'
 returnNextElement.next(value);
}

function* createFlow(){
 const data = yield fetch('http://respond.com/hi');
 // const data = 'hi from server';
 console.log(data);
}

const returnNextElement = createFlow();
// const futureData = fetch('http://responnd.com/hi');
const futureData = returnNextElement.next();
futureData.then(doWhenDataReceived);

Async Await 🧙

async function createFlow() {
  console.log("Me First");
  const data = await fetch("http://respond.com/hi");
  console.log(data);
}

createFlow();

console.log("Me second");

Exactly the same as the previous generator example, but with added 🍬

Observable 👁️

const button = document.querySelector('button');
const output = document.querySelector('output');

button.addEventListener('click', e => {
  output.textContent = 'clicked';
});
import { fromEvent } from 'rxjs';

const output = document.querySelector('output');  
const button = document.querySelector('button');

fromEvent(button, 'click')
  .subscribe(() => {
      output.textContent = 'clicked';
  });

Observable 👁️

import { fromEvent } from 'rxjs';
import { bufferCount } from 'rxjs/operators';

const output = document.querySelector('output');  
const button = document.querySelector('button');
      
fromEvent(button, 'click')
  .pipe(bufferCount(3))
  .subscribe(() => {
      output.textContent = 'clicked';
  });

Only update textContent of output on every third click.

Case for a Deeper Understanding

Fundamental understanding of the engine, execution context, scoping ⚙️

 

Reading the JavaScript spec 📜

https://timothygu.me/es-howto/

 

 

Experimenting with things like codesandbox 📦

 

Thank you!

Questions?

Truly Grasping Async and Concurrency In JavaScript

By Martin McKeaveney

Truly Grasping Async and Concurrency In JavaScript

  • 629