As far as I have seen then async/await, callbacks and promises are and can only be used to achieve asynchronous programming. Correct?

So my questions are:

1) Is it correct that the former three is used for asynchronous programming only?

2) If yes, then which of them is the best and why?

3) If no, then how they differ?

I was trying mssql module of node.js and I tried different ways:

Using Async/Await:

app.get('/app/users', async (res, req) => {
    try {

            const config=
                server: 'localhost',
                database: 'HimHer',
                user: 'sa',
                password: 'Jessejames01',
                port: 1433

            let pool = await sql.connect(config)
            let result1 = await pool.request().query('select top 1 * from dbo.Users');


        } catch (err) {
            // ... error checks

Using Promises:

sql.connect(config).then(pool => {
    // Query

    return pool.request().query('select * from dbo.Users')
}).then(result => {

}).catch(err => {
    console.log('Exception:+ '+err);

Using Callbacks:

 new mssql.connect(configuration, error => 
                new mssql.request().query('Select * from Users', (err, dataset) => 



Since all are achieving the same.

  • 2
    Sharing your research helps everyone. Tell us what you've tried and why it didn't meet your needs. This demonstrates that you've taken the time to try to help yourself, it saves us from reiterating obvious answers, and most of all it helps you get a more specific and relevant answer. Also see How to Ask
    – gnat
    Feb 12, 2019 at 20:55
  • @gnat: updated and please now upvote. Feb 12, 2019 at 21:00
  • Each is seen as an improvement on the prior.
    – Erik Eidt
    Feb 12, 2019 at 21:27
  • SO i should avoid others and use async/await always? Feb 12, 2019 at 21:31
  • 4
    "If binary machine code, assembly code, C, C++, Java, Perl, PHP, Python, Ruby, JavaScript, TypeScript, Lisp, Haskell, and Prolog all can be used to achieve programming then why don't we stick to one?" Or, also: "If German, Swedish, French, Russian, Spanish, and Mandarin all can be used to achieve communication then why don't we stick to one?" And also: "If GOTO, recursion, and WHILE loops all can be used to achieve Turing-completeness then why don't we stick to one?" Feb 13, 2019 at 1:57

3 Answers 3


The premise of your question is that having a single solution is the obvious choice. So why do we have:

  • More than one programming language?
  • More than one operating system?
  • More than one sort of car?
  • More than one sort of phone?
  • More than one sort of computer?

The answer is always the same. There are two types of versions: improvements and variants.

  • Improvements are flatout better than their predecessor and thus supplant them. For example, Windows 10 seeks to supplant Windows 8(.1).
  • Variants, however, bring some benefits at the cost of having some drawbacks. For example, Ubuntu vs Windows 10.

This means that variants don't supplant their predecessor, but instead simply offer a different option for consumers who care about the benefits (and are indifferent to the drawbacks) of this variant.

  • Callbacks are simple to understand and require no architectural dependecy, but when mismanaged can very quickly create code where the flow is obfuscated. Also, if the asynchronous method explodes and does not call the callback, it's hard to figure out that something went wrong.
  • Promises slighly improve on callbacks, and will handle errors more gracefully, but they lead to locally defined compositions. They do rely on somewhat of an architectural dependency.
  • Async/await is the more severe architecture-heavy option. It does away with most explicit handling and instead delegates the work to the runtime, but it more often leads to developers having to quess how the runtime will handle something because it's no longer explicitly readable from the code.

You seem to have reached the world of callbacks and async code recently. The reason there are multiple approaches is, like most things in programming, history.

The main asynchronicity in JS was in the form of events. Not much else was asynchronous at the beginning, and for events callbacks are essentially the only way. You also have timeouts and intervals, which also make sense to have as callbacks.

Then, AJAX came, animations came, and a lot of asynchronous web APIs started to appear. These are all explicit operations, but they're asynchronous, so the easiest and most obvious choice of interface is a callback.

At this point the concept of promises starts to appear. It already existed in other languages, of course, but it starts to come to JS. Treating async operations as objects sound nice, and the implementations of this concept were amaz

Then comes Node.js, where everything is asynchronous by design. The obvious choice in Node was to use callbacks, as no Promise standard existed at the time. Everything, therefore, uses a callback, and they standarize Node callbacks as receiving an error as the first argument, which can be null. Excellent, a standard!

But callbacks are terrible for complex code. If you did something serious, you likely needed to use something like async (the library, not the keyword) so your code wasn't hideous. This worked, everyone was happy. For the most part.

Promises starting to make way into Node. At this point, Promises A+ already exist and a native Promise standard is undereway. Libraries start using promises everywhere because it's so much better than using callbacks. And hey, promises and callbacks can be made compatible for the most part, so no problem in mixing code.

And then async/await comes. Note that this is just syntactic sugar for promises. As everybody loves promises, async/await is already supported everywhere. You don't have to use it, your users don't have to use it, it's a complement to promises. IMO, it's easier to read, but it's also less flexible than just promises, but you can just mix it so who cares!

So, tl;dr:

  • Callbacks are the overarching solution. It's the only way to solve the async problem for everything
  • Promises are glorified callbacks which simplify the callback hell. They came later out of a necessity to simplify things and make it simpler. They eventually standarized into Promises A`.
  • async/await is syntactic sugar for promises. It's the latest iteration, completely optional and fully compatible with Promises.

The answer, therefore, is: We use different approaches because of history. Most people use Promises or async/await now, but a lot of (mostly old) code still has callbacks.


Not too much of an expert on the topic, but I think they build off each other.

Callbacks are the lowest level and they work, but lead to a particular kind of mess (callback hell).

Promises clean up that mess nicely, but still lead to another smaller kind of mess.

async/await turn promises into code that's almost as clean as normal code.

Note that this is probably the order in which they should be learned, as well.

  • 1
    And the order in which they were introduced to JavaScript as language features and/or accepted programming patterns. Feb 12, 2019 at 21:05
  • 1
    And they were introduced in that order because the problems with one naturally led to the next. Feb 12, 2019 at 21:07
  • SO i should avoid others and use async/await always? Feb 12, 2019 at 21:31
  • Could you elaborate on the "smaller kind of mess" caused by Promises?
    – user949300
    Feb 12, 2019 at 22:11
  • @CodingManiac You "should" use async/await if you can, though I think promises and/or callbacks can do some things that async/await can't. Also, you should learn callbacks before promises, and promises before async/await. Feb 12, 2019 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.