Callbacks VS Promises VS Generators VS Async/Await
We will discuss the benefits and use case for each of the paradigm.
Callbacks
- Callback is a Higher-order Function
- Came as part of ES5
- Callback functions are derived from a programming paradigm known as functional programming
- Problem: Pyramid of Doom / Callback Hell – when too many callbacks are nested in one another, it becomes difficult to understand and predict the code.
example of simple callback
function One(a, cb){
cb(a+5);
}
One(4, (val)=> { //callback function
console.log(val);
});
Promises
- Use promises whenever you are using asynchronous or blocking code.
- Each promise is immutable
- Came as part of ES6
- Promises are used to avoid callback doom
- Promises are more powerful than callback as they are compose-able
- To run promises in parallel create an array of promises and then use
Promise.all(promisesArray)
- Promise methods:
Promise.prototype.catch(onRejected)
Promise.prototype.then(onFulfilled, onRejected)
Promise.prototype.finally(onFinally)
- Static methods:
Promise.reject(reason)
Promise.resolve(value)
Promise.all(iterable)
Promise.race(iterable)
const myFirstPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
// resolve(someValue); // fulfilled
// or
// reject("failure reason"); // rejected
});
Generators
- Came as part of ES6
- Generators are functions that you can use to control the iterator. They can be suspended and later resumed at any time.
- Yield returns a value only once, and the next time you call the same function it will move on to the next yield statement.
- Generators achieve yield delegation using chaining
- Generators return iterators, and it means we can actually iterate over it synchronously.
//ways of declaring generators
function * generator () {}
function* generator () {}
function *generator () {}
let generator = function * () {}
let generator = function* () {}
let generator = function *() {}
let generator = *() => {} // SyntaxError
let generator = ()* => {} // SyntaxError
let generator = (*) => {} // SyntaxError
class MyClass {
*generator() {}
* generator() {}
}
const obj = {
*generator() {}
* generator() {}
}
function * generator() {
yield 5;
}
const gen = generator();
gen.next(); // {value: 5, done: false}
gen.next(); // {value: undefined, done: true}
gen.next(); // {value: undefined, done: true}
For React Devs: Redux saga makes use of generators in sagas
function* ourSaga() {
yield take('START_REGISTRATION');
yield put(showLoginPopup());
}
sagaMiddleware.run(ourSaga);
Async/Await
- async function returns promise implicitly
- Came as part of ES7
- The async function automatically knows what to do if you await a Promise—it will pause the function (just like with generators) until the Promise resolves
async await
makes it much more easier to use promises. Developers from synchronous programming background will feel at home while usingasync
andawait
await
blocks the execution of the code within theasync
function in which it is located.- If the output of
function2
is dependent on output offunction1
then I useawait
. - If two functions can be run in parallel create two different
async functions
and then run them in parallel. - Promise creation starts the execution of asynchronous functionality.
- An asynchronous function is a function which operates asynchronously via the event loop, using an implicit
Promise
to return its result. - Every time you use
await
remember that you are writing blocking code. Over the time we tend to neglect this. - If your code contains blocking code it is better to make it an
async
function. By doing this you are making sure that somebody else can use your function asynchronously.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
var result = await resolveAfter2Seconds();
console.log(result);
// expected output: 'resolved'
}
asyncCall();