With ES6, JavaScript has added some powerful new features, one of them being async/await.
What async/await basically does is it lets you write asynchronous code that looks like synchronous code, making it much easier to reason about, and saving you from the callback pyramid of doom and promise hell.
It can basically turn this

doSomething.then(function (res) {
    // handle response
}).catch(function (err) {
    // handle error
})

to this

try {
    let res = await doSomething();
    // handle response
} catch (err) {
    // handle error
}

But the catch is that you can only use async await with code that is written in promise syntax. But what about the 70% of JavaScript code that uses callbacks? Well, here is how you can convert callback code to make it "awaitable"

function doSomething() {
    return new Promise(function (resolve, reject) {
        runCallbackFunction("abc", function (err, res) {
            if (err) reject(err);
            resolve(res);
        });
    });
}

And now you can use this previously callback-only function inside an async/await block!

async function doSomethingAsync() {
    try {
        let res = await doSomething();
        console.log(res);
        // handle response
    } catch(err) {
        console.error(err);
        // handle error
    }
}