For software development and maintenance, contact me at contact@appsoftware.com or via appsoftware.com


How to wrap a TypeScript JS callback with async await

Thu, 25 Feb 2021 by garethbrown

I find that at times the standard TypeScript/JavaScript callback pattern can make code hard to read and manage. To alleviate this problem, we can wrap callbacks with promises to synchronise the call. Going a step further, we can implement async / await to further improve code readability. This is especially true if like me, your primary programming language is OO like C# or Java.

In the below example, I’m working with NeDB, as JS database. Operations in NeDB follow the standard callback pattern. Standard callback pattern in the docs looks like this:

db.findOne({'name': 'draupnir'}, function (err, doc) {  
    console.log('findOne callback: err, doc', [err, doc]);  
});

In the async / await version below, we create an async function that wraps a promise, allowing us to call await to synchronise on the result. To allow for error handling in case promise reject() is called, we wrap the await in a try-catch-finally block.

In the standard promise version, we simply use findOnePromise.then() to inspect the result.

So, depending on your preference, you have some options …

///////////////////////
// async / await vesion
///////////////////////

let findOnePromiseFn = async (obj):Promise<any> => {

    return new Promise((resolve, reject) => {

        db.findOne(obj, function (err, doc) {

            if(err)
            {
                reject(err);
            }
            else
            {
                resolve(doc);
            }
        });
    })
}

// Trigger the function

let findOnePromise = findOnePromiseFn({'name': 'draupnir'});

// Potentially do other stuff ...

// Await the result

try
{
    let findOnePromiseResult = await findOnePromise;

    console.log('findOnePromiseResult', findOnePromiseResult);
}
catch (e)
{
    console.log('findOnePromiseResult (Error)', e);
}
finally
{
    // Any clean up
}
  
/////////////////////////////////
// standard promise based version
/////////////////////////////////
  
let findOnePromisFn = () => {

    return new Promise((resolve, reject) => {

        db.findOne({'name': 'draupnir'}, function (err, doc) {

            if(err)
            {
                reject(err)
            }
            else
            {
                resolve(doc);
            }
        });
    })
}

findOnePromisFn().then(
    value => {

        // Success

        console.log('findOnePromiseResult', value);
    }, 
    reason => {

        // Error

        console.error('findOnePromiseResult (Error)', reason);
    }
);

//////////////////////////////////
// Standard async callback version
//////////////////////////////////

db.findOne({'name': 'draupnir'}, function (err, doc) {

    console.log('findOne callback: err, doc', [err, doc]);
});

The information provided on this Website is for general informational and educational purposes only. While we strive to provide accurate and up-to-date information, we make no warranties or representations, express or implied, as to the accuracy, completeness, reliability, or suitability of the content, including code samples and product recommendations, presented on this Website.

The use of any information, code samples, or product recommendations on this Website is entirely at your own risk, and we shall not be held liable for any loss or damage, direct or indirect, arising from or in connection with the use of this Website or the information provided herein.
UI block loader
One moment please ...