Search code examples
javascriptasynchronousnode-mysql

JS basic design when I have naturaly sync code but I need to call a few async functions


Could you please help me to understand javascirpt async hell?

I think I am missing something important ☹ The thing is that js examples and most of the answers on the internet are related to just one part of code – a small snippet. But applications are much more complicated.

I am not going write it directly in JS since I am more interested of the design and how to write it PROPERLY.

Imagine these functions in my application:

InsertTestData();
SelectDataFromDB_1(‘USERS’);
SelectDataFromDB_2(‘USER_CARS’,’USERS’);
FillCollections(‘USER’,’USER_CARS’);
DoTheWork();
DeleteData();

I did not provide any description for the functions but I think it is obvious based on names. They need to go in THIS SPECIFIC ORDER. Imagine that I need to run a select into the db to get USERS and then I need run a select to get USER_CARS for these USERS. So it must be really in this order (consider the same for other functions). The thing is that need to call 6 times Node/Mysql which is async but I need results in specific order. So how can I PROPERLY make that happen?

This could work: /* not valid code I want to present the idea and keep it short */

InsertTestData(
 Mysql.query(select, data, function(err,success)
 {
SelectDataFromDB_1(‘USERS’); --  in that asyn function I will call the next procedure
 }  
 ));

SelectDataFromDB_1 (
 Mysql.query(select, data, function(err,success)
 {
SelectDataFromDB_2(‘USERS’); --  in that asyn function I will call the next procedure
 }  
 ));

SelectDataFromDB_2 (
 Mysql.query(select, data, function(err,success)
 {
FillCollections (‘USERS’); --  in that asyn function I will call the next procedure
 }  
 ));

etc..

I can “easily” chain it but this looks as a mess. I mean really mess. I can use some scheduler/timmers to schedule and testing if the previous procedure is done) Both of them are mess.

So, what is the proper way to do this;

Thank you, AZOR


Solution

  • If you're using a recent version of Node, you can use ES2017's async/await syntax to have synchronous-looking code that's really asynchronous.

    First, you need a version of Mysql.query that returns a promise, which is easily done with util.promisify:

    const util = require('util');
    // ...
    const query = util.promisify(Mysql.query);
    

    Then, wrap your code in an async function and use await:

    (async () => {
        try {
            await InsertTestData();
            await SelectDataFromDB_1(‘USERS’);
            await SelectDataFromDB_2(‘USER_CARS’,’USERS’);
            await FillCollections(‘USER’,’USER_CARS’);
            await DoTheWork();
            await DeleteData();
        } catch (e) {
            // Handle the fact an error occurred...
        }
    })();
    

    ...where your functions are async functions, e.g.:

    async InsertTestData() {
        await query("INSERT INTO ...");
    }
    

    Note the try/catch in the async wrapper, it's essential to handle errors, because otherwise if an error occurs you'll get an unhandled rejection notice (and future versions of Node may well terminate the process). (Why "unhandled rejections"? Because async functions are syntactic sugar for promises; an async function returns a promise.) You can either do that with the try/catch shown, or alternate by using .catch on the result of calling it:

    (async () => {
        await InsertTestData();
        // ...
    })().catch(e => {
        // Handle the fact an error occurred
    });