Javascript async

From wikinotes
Revision as of 22:08, 4 July 2021 by Will (talk | contribs) (→‎Timers)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

javascript is single threaded, but you can use an eventloop to perform tasks concurrently.

Documentation

promise docs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
async function docs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
concurrency and event loop https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

Timers

setTimer(fn, 2)     // enqueue fn() to run in 2s or more
setInterval(fn, 2)  // enqueue fn() every 2 seconds

Enqueued functions will be executed once the callstack is empty.

Promises

A promise is a unit of work that will be enqueued, resolved/executed asynchronously later.
Promises return promises, aside from async methods, you can only access their return value within a then method.

let promise = new Promise(
    (resolve, reject) => {
        resolve("foobar")
    }
)

Promise.resolve(promise)
    .then((value) => { console.log(value) },  // object from 'resolve()'
          (error) => { console.log(error) })  // object from 'reject()'

Since promises return promises, you can chain together several .then statements.
You can use .catch() to handle an error in any promise in the chain (or handle prev promise's value/return separately).

let promise = new Promise ((resolve, reject) => { reject("foobar") })

promise
    .then((value) => { console.log(value) })
    .then((value) => { console.log(value) })
    .then((value) => { console.log(value) })
    .catch((error) => { console.log(error) })
    .finally(() => { console.log("error or not, all done") })
// foobar
// error or not, all done

You can also use setTimeout() to delay enqueuing your message for N milliseconds (then it may take longer in the queue).

let promise = new Promise(
    function(resolve, reject) {
        setTimeout(function() { resolve(123) }, 100);
    }
);

Async Functions

Basics

Async functions operate on promises.
When await your_promise is called, your application will execute other code until your promise is fullfilled
then continue executing.

promise = new Promise((resolve, reject) => { resolve("value") })

// resolved before function returns!
async function waitForPromise(promise) {
    return await promise
}

// non async function, still resolved before function returns!
function waitForPromiseResolve(promise) {
    return Promise.resolve(promise)
}

Strategies

You chain multiple awaits in an async method and they will all be executed before the function returns.
There are 3x strategies available:

  • synchronous (await each promise, each takes max time)
  • concurrenct (enqueue each promise, then wait on all, only applicable to setTimeout I think)
  • parallel (use Promise.all() and multiple will be run at once.

synchronous

// foo_promise and bar_promise are enqueued and awaited
// one at a time. slowest!
async function runPromisesSynchronous() {
    let foo_promise = await new Promise((resolve, reject) => { resolve("foo") })
    let bar_promise = await new Promise((resolve, reject) => { resolve("bar") })
    return foo_promise + bar_promise
}

concurrent

// foo_promise and bar_promise are enqueued!
let foo_promise = new Promise((resolve, reject) => { resolve("foo") })
let bar_promise = new Promise((resolve, reject) => { resolve("bar") })

// now retrieve values (they may both already be done)
async function runPromisesAsync(promise) {
    return await foo_promise + await bar_promise
}

parallel

// run both promises at the same time
async function runParallel() {
    Promise.all([
        (async()=>await new Promise((resolve, reject) => { resolve("foo") }))(),
        (async()=>await new Promise((resolve, reject) => { resolve("bar") }))(),
    ])
}

Source https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

TODO:

How many I/O libraries use async/await? Anything builtin to javascript?
How does parallelism in Promise.all() work under the hood?