0

Confused with the best practises.

Using async-await is better than using promises. Is it right ?

How to determine the use of aync/await and promises ?

Below I just wrote two code snippets. One with using aync/await and another without it.

Which will be faster?

What is the advantage of CASE 1 ?

Which is newest method and advantage over another ?

CASE 1

var promise1 = rp('https://api.example.com/endpoint1');
var promise2 = rp('https://api.example.com/endpoint2');

var response1 = await promise1;
var response2 = await promise2;
return response1 + ' ' + response2;

CASE 2

var promise1 = rp('https://api.example.com/endpoint1');
var promise2 = rp('https://api.example.com/endpoint2');

return Promise.all([promise1, promise2])
.then(function(values){
    return values[0] + values[1];
});
Ashwanth Madhav
  • 1,084
  • 1
  • 9
  • 21
  • 4
    `async/await` is *for* `Promises` not vs `Promises` – Yury Tarabanko Jul 29 '19 at 12:16
  • Can you please review the two cases and what's the difference between them? – Ashwanth Madhav Jul 29 '19 at 12:17
  • Async/await is just fancy syntax to write promises. So most will come down to preference. Case 1 is shorter to write. Case 2 makes it harder to miss that the function is async. I'm one of those people who finds promise chains easier to follow. – Shilly Jul 29 '19 at 12:19
  • 3
    @slideshowp2 — No. The promises are both initialised before *either* is `awaited`. They will execute in parallel in both cases. – Quentin Jul 29 '19 at 12:20
  • Your cases are almost identical. But if you did `var r1 = await rp('https://api.example.com/endpoint1'); var r2 = await rp('https://api.example.com/endpoint2')` The behaviour would be different: requests would run sequentually. – Yury Tarabanko Jul 29 '19 at 12:20
  • Is executing parallel better than await? – Ashwanth Madhav Jul 29 '19 at 12:20
  • See [this question](https://stackoverflow.com/questions/46889290/waiting-for-more-than-one-concurrent-await-operation) on why CASE1 is outright dangerous. You should always use `Promise.all` - and of course you can use it together with `await` instead of `then`. – Bergi Jul 29 '19 at 12:36

5 Answers5

5

Using async-await is better than using promises

No. async and await are tools to help you manage promises.

Which will be faster?

There's unlikely to be any noticeable difference

What is the advantage of CASE 1 ?

Some people would consider it simpler and easier to understand. Others might disagree.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • In the CASE 2 , executing promises in parellel. In CASE 1 one after another. – Ashwanth Madhav Jul 29 '19 at 12:23
  • response2 will get only after getting response1. Is it write ? – Ashwanth Madhav Jul 29 '19 at 12:23
  • 2
    @AshwanthMadhav — No. They execute in parallel in both cases. The async process begins when `rp()` is called. That function returns a promise. The calling function goes to sleep when the `await` statement is reached. That is *after* **both** calls to `rp`. i.e. it doesn't go to sleep before the second call to `rp()` so there is no delay in the second async process starting. – Quentin Jul 29 '19 at 12:25
  • Currently I'm working with the same concept as @kuba says. I can't understand the two await working at the same time. When we are consoling after each await line, Before going to this line `var response2 = await promise2;`, I can print the result of `respons12` – Ashwanth Madhav Jul 29 '19 at 12:34
  • [CASE1 is not simpler, but simply wrong](https://stackoverflow.com/questions/46889290/waiting-for-more-than-one-concurrent-await-operation). – Bergi Jul 29 '19 at 12:37
  • @AshwanthMadhav await does not start promise. Promise is an object that you can treat like a handle to an operation that eventually finishes. It may contain some result when it finishes but it might not. The promise's code starts working not when you starts awaiting it but when Promise is created so in your example when you invoke `rp` function. If you would do something like I presented in my (updated) answer, the behaviour would be indeed different. – Eltu Jul 29 '19 at 12:44
  • When we are awaiting a 100 promises and running it with promise.all() is different. Promise.all get the result first. – Ashwanth Madhav Jul 29 '19 at 12:56
  • @AshwanthMadhav — No. – Quentin Jul 29 '19 at 12:57
  • I experienced it when fetching data from DB with promise.all is faster than await – Ashwanth Madhav Jul 29 '19 at 12:59
  • @AshwanthMadhav — Seems unlikely unless you changed the structure of your code too. – Quentin Jul 29 '19 at 13:01
  • Let me try once more. – Ashwanth Madhav Jul 29 '19 at 13:10
  • the first case is not similar to the second one as pointed out by many others. It will perform async operations one by one instead of performing in parallel like second case – Ganesh Karewad Jul 30 '19 at 07:06
  • @GaneshKarewad — No, it won't. I've explained why already. In **this** comment thread. Kuba Michałek has explained why too. – Quentin Jul 30 '19 at 07:39
2

Async/await is translated into a Promise under the hood.

Hence, the performance of both is the same.

You should always use async/await, unless there's some technical limitation, as it's easier to understand.

Now, as other mentioned, two code examples are not equal at the moment. But since you're using await, it means that your rp() returns a promise. So, you could rewrite your first case as:

let [r1, r2] = await Promise.all([promise1, promise2])
return r1 + r2

To achieve same results.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Alexey Soshin
  • 16,718
  • 2
  • 31
  • 40
0

Using async-await is better than using promises.

Which will be faster?

Which is newest method and advantage over another?

Neither syntax nor either of your approaches offers any particular advantage over the other, but additionally, your approaches don't display your intent well. You don't need to keep explicit references to the promises in order to get their results concurrently:

const [response1, response2] = await Promise.all([
  rp('https://api.example.com/endpoint1'),
  rp('https://api.example.com/endpoint2')
]);
...

Keep in mind the above approach must be contained within an async function. It cannot exist at top-level scope like this approach:

Promise.all([
  rp('https://api.example.com/endpoint1'),
  rp('https://api.example.com/endpoint2')
]).then(([response1, response2]) => {
  ...
});
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • But for when using await the next line is executed after getting the result only. There is two awaits. So waiting for both responses. Promise.All doing the things in parallel. Then how async become better? Is it just for understanding? – Ashwanth Madhav Jul 29 '19 at 12:26
  • @AshwanthMadhav `There is two awaits`. I'm not quite sure what you mean there. There's only one `await`. `Then how async become better?` It doesn't. It's a matter of style preference. Use whichever approach makes your code more readable and easier to understand, there is virtually no performance difference, and certainly no difference that you should care about between these two examples other than style. – Patrick Roberts Jul 29 '19 at 12:30
  • When consoling under response1, there is the result of that promise. same way, When consoling under response2, there is a result. But there is a time for resolving both the promises – Ashwanth Madhav Jul 29 '19 at 12:37
  • @AshwanthMadhav your comment still doesn't make sense. Are you talking about the example I provided or no? – Patrick Roberts Jul 29 '19 at 13:56
0

All current responses are of course correct but please keep in mind some differences.

Currently in both your solutions promises are invoked in parallel. This might lead to some errors.

Consider such case (slight modifications to your case 1):

var response1 = await rp('https://api.example.com/endpoint1');
var response2 = await rp('https://api.example.com/endpoint2');

return response1 + ' ' + response2;

In above case promise2 will be executed AFTER promise1 finishes executing itself. The result is already known when promise2 is started. Your cases, on the other hand, run them all together in some kind of a race. Therefore if in second call to rp would contain logic that depends on some action that is done in first call to rp, it might lead to unexpected results or even to crash. Good example would be writing and reading to the same file.

Let's consider following example:

function writeToFile()
{
   return new Promise((resolve, reject) => {
      ... // writing to file abc.txt
   };
}

function readFile()
{
   return new Promise((resolve, reject) => {
      ... // reading file abc.txt
   };
}

function raceCondition() 
{
   Promise.all([
       writeToFile(),
       readFile()
   ]);
} 

async function asyncAwait() 
{
   await writeToFile();
   await readFile();
} 

raceCondition() function might lead to unexpected behavior because readFile might be run while writeToFile function did not even finish writing to the file. It could lead to reading some old data, or even file might not even exist.

asyncAwait() function uses async/await approach that guarantees that writeToFile() function finishes its work before reading starts. Of course it does not mean that the program becomes synchronous. In the meantime other operations are performed (i.e. some GUI events processing etc).

Async/Await should be then considered as an alternative to .then().then() chain rather than to Promise.all

Eltu
  • 470
  • 4
  • 11
  • Here the readFile is executed only after writeToFile. In my case, there is no need to get one after another. Both will execute parallelly may better for me. Both functions are independent. – Ashwanth Madhav Jul 29 '19 at 12:54
  • Yes, you are right, just wanted to pinpoint the possible pitfall in using `Promise.all` – Eltu Jul 29 '19 at 13:21
0

Await is used to evaluate a resolved or rejected Promise. So the functionality is the same using .then and await. However await makes for way more readable code as you don't get into a a series of callbacks. With await you can rather treat your async function as a sync function using await.

Let us take an example. We have an API and 2 databases, we want to take a name from one of the databases and insert into another database. For us to do that we would have to fetch the data from Database 1. Wait for it to arrive to our client to then send it over with a POST request to our API to insert. [ You could do all of this with ONE function server side but for our case we are going to make 2 async fetch request to answer this question ]. If we wanted to solve this using .then in a function it would look something like this.

function get_and_set(){
   fetch("https://www.some_api.com/get_random_name")
   .then( response => response.text() )
     .then( name => {
       fetch("https://www.some_api_2.com/insert_name", {
        headers : {
          "Body-Type"    : "application/json",
          "Accept"       : "application/json"
        },
        method : "POST",
        body : JSON.stringify({ name : name })
      })
      .then( set_response => set_response.text() )
        .then( set_response => {
           return set_response;
        })
     )}

}

If we instead were to choose to use an async function with await we could write as this instead. Which becomes more readable in my personal opinion.

async function get_and_set(){
  let response = await fetch("https://www.some_api.com/get_random_name")
  let name = response.text();

  let insert_response = await fetch("https://www.some_api_2.com/insert_name", {
     headers : {
        "Body-Type"    : "application/json",
        "Accept"       : "application/json"
     },
     method : "POST",
     body : JSON.stringify({ name : name })
  });
  let success = insert_response.text();

  return (success); //Return the status of how the insertion went
}
Albin wärme
  • 251
  • 1
  • 14