Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: Which parts of the code are executed following an asynchronous call?

Asynchronous calls are an inherent part of javascript, and using callbacks is often an elegant tool to handle these calls.

However, I am not quite sure how is the branching of code following an asynchronous operation decided. For example, what would happen with the following code?

function f(callback) {
   value = some_async_call();
   if (value) {
       callback(value);
   }
   return(value);
}

What would happen here? From my short JS experience, return would send back an undefined value. But suppose that value returns true from the asynchronous call, would the callback be called with the right value or with an undefined value?

In other words, is there a rule regarding which operations are executed immediately after the async call, and which are deferred until the value is returned?

What have I tried before asking

SFTW for branching asynchronous calls in javascript, but found nothing canonical or decisive.

like image 967
Adam Matan Avatar asked Apr 18 '17 10:04

Adam Matan


1 Answers

update: added a practical difference between the 3 different approaches at the bottom

let's assume some_async_call(); is defined as an async function: async function some_async_call() { ... }

what this function returns is a Promise, which means that value is now a promise: value.then( function(result) { } )

when i translate this into code:

async function some_async_call() { 
    if (theMoonIsInTheRightPosition)
        return Fetch('/api/data/') // this returns a promise as well.

    return false;
}

i can now do 2 things:

function parentFunction(callback) {
    var promise = some_async_call();
    promise.then( callback );
    return ...; // you can't "return" the value of an async call synchronously, since it is a promise.
}

or:

async function asyncParentFunction( callback ) {
    var value = await some_async_call();
    if (value)
        callback( value );
    return value;
}

however, this transforms the parent-function into an async function as well, which means the immediate return value of that function... is a promise as well.

Long story short:

You either use callbacks to flow through your asynchronous functions, or promises, or async/await

callbacks

function doStuff(callback) {
    // do asynchronous stuff
    var result = 100;
    callback(result); // once you're done with stuff
}
doStuff( function(data) { console.log('Im done!', data); } );

promises

function doStuff() {
    return new Promise(function(resolve, reject) {
        // do asynchronous stuff
        var result = 100;
        resolve(result);
    });
}
doStuff.then(function(data) { console.log('Im done!', data); });

async/await

function doStuff() {
    return new Promise(function(resolve, reject) {
        // do asynchronous stuff
        var result = 100;
        resolve(result);
    });
}
(async function() { // async/await only works in async functions.
    var data = await doStuff();
    console.log('Im done!', data);
})();

as you can see: promises and async/await use the same mechanism and are really worth reading into.

a practical example of the difference between the three:

callbacks

function fetchUserWithPosts(userId, callback) {
    fetchUser(userId, function(user) {
        fetchPostsByUserId(userId, function(posts) {
            callback({
                user: user,
                posts: posts
            });
        });
    });
}

promises

function fetchUserWithPosts(userId) {
    return Promise.all([
        fetchUser(userId),
        fetchPostsByUserId(userId)
    ]).then(function(result) {
        return {
            user: result[0],
            posts: result[1]
        };
    });
}

async/await

async function fetchUserWithPosts(userId) {
    return {
        user: await fetchUser(userId),
        posts: await fetchPostsByUserId(userId);
    };
}
like image 174
DoXicK Avatar answered Sep 26 '22 11:09

DoXicK