116

I have a simple code in JavaScript that execute a request in an API and return the response, simple. But in this case I will have thousands of requests. So, which one of the code options will perform better, and why. Also which one is recommended as good pratices these days?

First options is using the .then to resolve the promises and the seccond one is using async / await.

In my tests the two options had very similar results without significant differences, but I'm not sure in scale.

// Using then
doSomething(payload) {
  const url = 'https://link-here/consultas';
  return this.axios.get(url, {
    params: {
      token: payload.token,
      chave: payload.chave,
    },
   }).then(resp => resp.data);
}

// Using Async / await
async doSomething(payload) {
   const url = 'https://link-here/consultas';
   const resp = await this.axios.get(url, {
   params: {
     token: payload.token,
     chave: payload.chave,
    },
 });
 return resp.data;
}

Any explanation will be of great value.

Francisco
  • 1,307
  • 2
  • 8
  • 7
  • 2
    Hi there! Take a look at https://blog.pusher.com/promises-async-await/ . And do not forget to wrap your async/await code with try/catch block. – Nikolay Vetrov Feb 02 '19 at 17:44
  • 7
    Performance difference should not really be something to bother about: surely the http requests take >99% of the execution time anyway. A real gain can be got if you can launch a few requests in parallel, and join their responses with `Promise.all`. Then launch the next batch, ...etc. – trincot Feb 02 '19 at 17:54
  • 4
    I am not sure if this can be applied here, but see this general advise [at the end of this article](https://v8.dev/blog/fast-async#conclusion) from the V8 developers: "favor `async` functions and `await` over hand-written promise code". – vsemozhebuty Feb 02 '19 at 18:25
  • 3
    @NikolayVetrov - There's no reason to wrap `await` here in a `try/catch`. The OP just wants to return the rejected promise anyway and the `async` function will catch the rejection and do that automatically. `try/catch` would be needed and useful in more complicated error handling situations than this. – jfriend00 Feb 02 '19 at 20:16

8 Answers8

182

From a performance point of view, await is just an internal version of .then() (doing basically the same thing). The reason to choose one over the other doesn't really have to do with performance, but has to do with desired coding style or coding convenience. Certainly, the interpreter has a few more opportunities to optimize things internally with await, but its unlikely that should be how you decide which to use. If all else was equal, I would choose await for the reason cited above. But, I'd first choose which made the code simpler to write and understand and maintain and test.

Used properly, await can often save you a bunch of lines of code making your code simpler to read, test and maintain. That's why it was invented.

There's no meaningful difference between the two versions of your code. Both achieve the same result when the axios call is successful or has an error.

Where await could make more of a convenience difference is if you had multiple successive asynchronous calls that needed to be serialized. Then, rather than bracketing them each inside a .then() handler to chain them properly, you could just use await and have simpler looking code.

A common mistake with both await and .then() is to forget proper error handling. If your error handling desire in this function is to just return the rejected promise, then both of your versions do that identically. But, if you have multiple async calls in a row and you want to do anything more complex than just returning the first rejection, then the error handling techniques for await and .then()/.catch() are quite different and which seems simpler will depend upon the situation.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    Right. And another benefit using 'await' is that the function is clearly marked – Tal L Nov 01 '21 at 15:21
  • Great answer. As someone new to async paradigm what I find very confusion is when both styles are mixed, some `.then` and some `await` but I guess this is just a layout or stylistic choice? e.g. this example code: https://github.com/databricks/databricks-sql-nodejs/blob/55556890c022062dec5f2243ec7b9bae7f9c06ac/examples/session.js#L11 – Davos Aug 08 '22 at 14:05
  • 3
    @Davos - Not really a stylistic choice. It is generally not recommended to mix `await` and `.then()` as it just makes the code more complicated to follow and understand. Generally, `await` will be simpler code to write and follow if it can be used. – jfriend00 Aug 08 '22 at 20:47
  • Then() gives you more reactive outcome and non ui blocking results. I also noticed you may experience more time child render with then() and also observed await blocks ui - react native. – maddy May 30 '23 at 15:35
  • 1
    @maddy - `await` does NOT block the UI by itself. `await` does not block the JS interpreter at all. If you `await` something and don't render until after the `await`, then the UI will not render until after the promise resolves, but that's your own code. That's not because of `await`. The same thing would happen if you rendered inside a `.then()` handler. Either way, they have to wait for the asynchronous operation to complete before the render happens and this has nothing at all to do with `await` vs. `then()`. It has to do with how your code is written with either. – jfriend00 May 30 '23 at 21:14
  • Thanks for sharing this valuable insights i still need to understand this. In my app when I was using await I noticed visually and experienced lags specially when I navigate to new screen , once I change my api calls with then visually I experience non blocking user interactions. – maddy Jun 08 '23 at 14:51
51

There should be some corrections in this thread. await and .then are going to give very different results, and should be used for different reasons.

await will WAIT for something, and then continue to the next line. It's also the simpler of the two because it behaves mechanically more like synchronous behavior. You do step #1, wait, and then continue.

console.log("Runs first.");
await SomeFunction();
console.log("Runs last.");

.then splits off from the original call and starts operating within its own scope, and will update at a time the original scope cannot predict. If we can put semantics aside for a moment, it's "more asynchronous," because it leaves the old scope and branches off into a new one.

console.log("Runs first.");
SomeFunction().then((value) => {console.log("Runs last (probably). Didn't use await on SomeFunction().")})
console.log("Runs second (probably).");
user280209
  • 675
  • 5
  • 5
  • 8
    Why would await/.then give different results. They're designed to do the same thing just with different syntax. Second, `await` isn't technically blocking behavior in that it doesn't block the thread. And I wouldn't describe `.then` as being "more asynchronous". They're both just as asynchronous, and I don't think it's helpful to think about it like this. – pushkin Aug 30 '21 at 20:59
  • Please provide additional details in your answer. As it's currently written, it's hard to understand your solution. – Community Aug 30 '21 at 20:59
  • 2
    I added some clarity to demonstrate what I mean. These are two very different functions. And obviously more discussion is involved in async, which belongs in a full guide, and I clearly prefaced the statement with "if we put semantics aside." – user280209 Aug 30 '21 at 23:22
  • You are commenting on something that was not asked in the question at all. The question is purely about performance reason to choose one over the other, not all the other coding reasons or not all the other differences. Look at the op's two code samples. They are asking about the difference between those and nothing more. Your answer isn't wrong information, but it is not an answer to what is being asked. – jfriend00 Sep 09 '22 at 03:36
  • @jfriend00 He pretty clearly states that `then` creates a new scope. I suppose he could expound on the lower level details, but creating a scope requires memory (and management). So, based on that alone, that basically tells you `then` does not perform as well as `await`, particularly in the case of loops, where, with `then`, you _must_ use recursion, which means all promises remain in memory until the loop terminates.. the async version of said loop wouldn't have the same issues. – gabriel.hayes Mar 16 '23 at 01:25
33

As more explanation to @user280209 answer let's consider the following function which returns promise and compare its execution with .then() and async await.

function call(timeout) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`This call took ${timeout} seconds`);
      resolve(true);
    }, timeout * 1000);
  });
}

With .then()

(async () => {
  call(5).then((r) => {
    console.log(r);
  });
  await call(2); //This will print result first
  await call(1);
})();

When running the above call the logs will be

This call took 2 seconds
This call took 1 seconds
This call took 5 seconds
true

As we can see .then() didn't pause the execution of its below line until it completes.

With async/wait

(async () => {
  await call(5); //This will print result first
  await call(2); 
  await call(1);
})();

When run the above function logs will be

This call took 5 seconds
This call took 2 seconds
This call took 1 seconds

So I think if your promise's result won't be used in the following lines, .then() may be better.

Nux
  • 5,890
  • 13
  • 48
  • 74
  • 2
    thanks for the examples! on the first `call(5).then`, will its execution continue in the background while you wait for `await call(2)` and `await call(1)` ? – Doug Jan 12 '22 at 00:53
  • While this information is not inaccurate, what does it have to do with the performance question that is being asked here? I don't see anywhere that you even commented on the op's two code blocks and the performance difference between them. That's the question being asked here. – jfriend00 Sep 09 '22 at 03:39
  • 3
    @jfriend00 the second to last paragraph in your answer seems to imply await and then have the same behavior and that their only difference is that await is shorter to type. This+user280209's answer clarify how this is not the case, they have a clear difference. It's true this is not explicitly relevant to the Question, but adding this gives info that's implicitly important if one wants to understand await vs then better. – Juan Perez Sep 11 '22 at 12:19
  • If you have only a single asynchronous operation as shown in the code the op is asking about, then it makes no difference if you use `.then()` and return the promise or use `await`. Either way same result so it's just an individual coding preference. As I say in my answer `await` has coding simplicity advantages when there is more than one asynchronous operation to run in sequence. – jfriend00 Sep 12 '22 at 03:34
  • 2
    It's worth mentioning that the wall time of the `.then()` example is 3 seconds, while the wall time of the `async` example is 8 seconds. In other words, each `await` pauses the thread and literally *waits* for the result, while `.then()` runs asynchronously. – Ben Feb 16 '23 at 03:17
  • @Ben that's what I feel and experience on UX. – maddy Jun 08 '23 at 14:59
8

For those saying await blocks the code until the async call returns you are missing the point. "await" is syntactic sugar for a promise.then(). It is effectively wrapping the rest of your function in the then block of a promise it is creating for you. There is no real "blocking" or "waiting".

run();

async function run() {
    console.log('running');
    makePromises();
    console.log('exiting right away!');
}

async function makePromises() {
    console.log('make promise 1');
    const myPromise = promiseMe(1)
    .then(msg => {
        console.log(`What i want to run after the promise is resolved ${msg}`)
    })
    console.log('make promise 2')
    const msg = await promiseMe(2);
    console.log(`What i want to run after the promise is resolved via await ${msg}`)
}   

function promiseMe(num: number): Promise<string> {
    return new Promise((resolve, reject) => {
        console.log(`promise`)
        resolve(`hello promise ${num}`);
    })
}

The await line in makePromises does not block anything and the output is:

  • running
  • make promise 1
  • promise
  • make promise 2
  • promise
  • exiting right away!
  • What i want to run after the promise is resolved hello promise 1
  • What i want to run after the promise is resolved via await hello promise 2
spidermonk13
  • 89
  • 1
  • 1
  • 3
    If using await puts the tail of the function in .then block, it really does cause different behavior. – Siavoshkc Jun 15 '22 at 07:31
  • 1
    Just change the order of Promise2 (async) and Promise1 (then) creation in the makePromises() function and you will see that await indeed blocks. And you get the following output: `running; make promise 2; promise; exiting right away!; What i want to run after the promise is resolved via await hello promise 2; make promise 1; promise; What i want to run after the promise is resolved hello promise 1;` **Note how "make promise 1" does not get printed until promise 2 is resolved. ** – 2020 Jul 11 '22 at 04:34
  • Note that when you swap the promise2 and promise1, "make promise 1" does not get printed until promise 2 is resolved. When we say await blocks, it only blocks the function in which await happens, that is the makePromises fn and not the 'run' function ! – 2020 Jul 11 '22 at 04:46
5

Actually. Await/Async can perform more efficiently as Promise.then() loses the scope in which it was called after execution, you are attaching a callback to the callback stack.

What it causes is: The system now has to store a reference to where the .then() was called. In case of error it has to correctly point to where the error happens, otherwise, without the scope (as the system resumed execution after called the Promise, waiting to comeback to the .then() later) it isn't able to point to where the error happened.

Async/Await you suspend the exection of the method where it is being called thus preserving reference.

Adam Smooch
  • 1,167
  • 1
  • 12
  • 27
Raphael Viana
  • 67
  • 1
  • 2
4

If we just consider performance(time taken) then it actually depends on whether your operations are serial or parallel. If your tasks are serial then there will be no difference between await and .then. But if your tasks are parallel then .then will take less time. Consider the following example

let time = Date.now();

// first task takes 1.5 secs 
async function firstTask () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1);
        },1500)
    })
}

// second task takes 2 secs 
async function secondTask () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2);
        },2000)
    })
}

// using await
async function call(){
    const d1 = await firstTask();
    const d2 = await secondTask();
    console.log(Date.now()-time, d1+d2)
}
call()


// using .then
async function call2(){
    let d1=null,d2=null;
    firstTask().then(data => {
        d1=data;
        if(d2){
            console.log(Date.now()-time, d1+d2);
        }
    })
    secondTask().then(data => {
        d2=data;
        if(d1){
            console.log(Date.now()-time, d1+d2);
        }
    })
}
call2()

Here are the two tasks, first takes 1.5 secs and second takes 2 secs. Call function uses await where as call2 function uses .then . The output is as follows

From call2  2012 3
From call  3506 3

I hope it helps.

Sahil Rajpal
  • 510
  • 4
  • 8
2

As far as I understand .then() and await are not the same thing. An async function won't proceed with the next command until the promise is resolved/rejected since it's basically an implementation of generators. On the contrast, in the case of .then(), the execution of the function will proceed with the next command and the resolve/reject callback will be executed "when there's time" aka when the current event loop (not entirely sure about that part) will be completed.

tldr; on a single promise await and .then() behave similarly but when one promise needs another one to be resolved first then the two of them behave entirely different

GMalliaris
  • 21
  • 1
0

Many answer have been provided to this question already. However, to point out key information in the answers above and from my understanding, note below point:

  • only use await when not handling error return
  • if no crucial need for error handling use await instead
  • use .then .catch if returned error message or data is crucial for debugging / or proper error handling instead of try catch for await

Choose any prefer method from code sample below

const getData = (params = {name: 'john', email: 'ex@gmail.com'}) => {
  return axios.post(url, params);
}

// anywhere you want to get the return data

// using await

const setData = async () => {

  const data = await getData();
  
  }
  
  // to handle error with await
  const setData = async () => {
    try {
      const data = await getData();
      }
     catch(err) {
        console.log(err.message);
     }
  }
  
   // using .then .catch
  const setData = () => {
 
      var data; 
      getData().then((res) => { 
        data = res.data; console.log(data)
      }).catch((err) => {
        console.log(err.message);
      });

  }