JavaScript: Asynchronous

Closures & Time Dependency

let capturedVar = “Starting”;
setTimeout( () => console.log(capturedVar) , 10000);   // performs function after 10000 mSec
capturedVar = “Ending”;
  • Code outputs “Ending” after 10 seconds
  • “Closure” = something that uses a “captured variable”
  • In Java captured variables must be “effectively final” to stop them changing unexpectedly, not so in JavaScript.
  • Closure behaviour is unpredictable & care must be exercised.

Promises

Not everything happens immediately. Some things take time. JavaScript is not multithreaded so you cannot create a thread to sit dormant while work is done elsewhere. As a result JavaScript operates on the basis of callbacks.

  1. call a function to do something and pass in a “callback function” to be called when it completes.
  2. when the work is done the callback function is executed.

The processing flow is disjointed. Work has to be sliced up into callback functions and chained together.

JavaScript ‘promises’ offer a framework for managing units of asynchronous work. Promises, once defined, can be chained together.

const myFunc = () => {  // A function that does something. In this case not much.
	return "Hello";
}
const myPromise = new Promise( (resolve, reject) =>{
			const callback = () => resolve( myFunc() );
			setTimeout(callback , 3000);
		});

myPromise.then( ret => { console.log(ret); } );

A promise:

  • for managing asynch processing. Unnecessary for synchronous processing.
  • once inside the promise/asych world, data cannot return to main flow/synch world
  • must be either “Resolved” (successful) or “Rejected” (failure).
  • All exceptions must be caught and handled (probably invoking “rejected”).
  • Status ‘pending’ → ‘resolved’ or ‘rejected’, ‘resolved’ → ‘fulfilled’
  • once complete (resolved or rejected) → ‘settled’

Can turn any value into a promise – used when mixing synch/asynch data:

Promise.resolve(value);

To use contents of a promise must use .then(nextFunc, rejectFunc)

  • produces another promise → allows for chaining
  • parameter of .then() is always a function to be performed when the previous promise has completed
  • can use .catch(catchFunction) to catch unhandled rejections
  • can use .finally(finalFunction) to close resources

Can create an array/iterable of promises to be called as a group:

Promise.all(myPromiseArray).then(returnIter => …)

Order of invocation not assured but the results will be in the same order as the call.

Promise.allSettled() also available as are Promise.race(promiseArray) & Promise.any(promiseArray) for “winner takes all” processing.

Asych / Await

A syntax to simplify the use of promises. The promises are still required but the syntax replaces the .then() chains.

Using the myPromise above to define an “async” function. In the function, “await” the result of a promise.

async function asynchFunc(inValue){
	const ret = await myPromise;
	console.log(inValue + "   " + ret);
}

The code is not executed in this manner: execution does not stop and wait for anything. The await keyword indicates to the interpreter to create .then() processing for the following lines.

When the function is called in the normal manner it enters the async world and will return another promise (the value returned from the asynchFunc).

let anotherPromise = asynchFunc("me");

The async keyword can be used before:

  • arrow functions
  • methods
  • functions
  • object literal methods