Difference of using async / await vs promises? - javascript

I am looking for a answer on what to use in my nodeJS app.
I have code which handles my generic dB access to mssql. This code is written using an async functions and then I used a promise to call that function and all works fine.
As my app is getting bigger and code larger I am planning to move some of the logic into functions and then call them.
So my question is: is there a drawback to using a mix of async/await and promises or does it really not matter?
Async / await makes it easier to write more readable code as I have to read and write to multiple db’s before I return something and I need results of some of these.
So the question is what is the better approach?
Async / await on dB layer that’s set and can’t change
The logic layer async / await which would allow me a async / and await on the function call or if I go with promise for logic then I am stuck with promise on function call.
So I hope someone can give me more insight if one has more advantages than the other, besides being able to write cleaner code.

async/await and promises are closely related. async functions return promises, and await is syntactic sugar for waiting for a promise to be resolved.
The only drawback from having a mix of promises and async functions might be readability and maintainability of the code, but you can certainly use the return value of async functions as promises as well as await for regular functions that return a promise.
Whether you choose one vs the other mostly depends on availability (does your node.js / browser support async?) and on your aesthetic preference, but a good rule of thumb (based on my own preference at the time of writing) could be:
If you need to run asynchronous code in series: consider using async/await:
return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);
If you need nested promises: use async/await:
return asyncFunction()
.then(result => {
return f1(result)
.then(result2 => f2(result, result2);
})
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);
If you need to run it in parallel: use promises.
return Promise.all(arrayOfIDs.map(id => asyncFn(id)))
It has been suggested you can use await within an expression to await multiple tasks like so:
*note, this still awaits in sequence from left to right, which is OK if you don't expect errors. Otherwise the behaviour is different due to fail fast behaviour of Promise.all()
const [r1, r2, r3] = [await task1, await task2, await task3];
(async function() {
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Create Promises');
const task1 = t1(100);
const task2 = t1(200);
const task3 = t1(10);
console.log('Await for each task');
const [r1, r2, r3] = [await task1, await task2, await task3];
console.log('Done');
}())
But as with Promise.all, the parallel promises need to be properly handled in case of an error. You can read more about that here.
Be careful not to confuse the previous code with the following:
let [r1, r2] = [await t1(100), await t2(200)];
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() => {
console.log('Await');
let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
});
Using these two methods is not equivalent. Read more about the difference.
In the end, Promise.all is a cleaner approach that scales better to an arbitrary number of tasks.

Actually it depends on your node version, But if you can use async/await then your code will be more readable and easier to maintain.
When you define a function as 'async' then it returns a native Promise, and when you call it using await it executes Promise.then.
Note:
Put your await calls inside a try/catch, because if the Promise fails it issues 'catch' which you can handle inside the catch block.
try{
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
}
catch(ex){
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
}
also you can handle your 'catch' like this:
let result = await your-asyncFunction(parameters).catch((error)=>{//your error handler goes here});
this method mentioned does not produce an exception so the execution goes on.
I do not think there is any performance difference between async/await other than the native Promise module implementation.
I would suggest to use bluebird module instead of native promise built into node.

At this point the only reason to use Promises is to call multiple asynchronous jobs using Promise.all() Otherwise you’re usually better with async/await or Observables.

Its depending upon what approach you are good with, both promise and async/await are good, but if you want to write asynchronous code, using synchronous code structure you should use async/await approach.Like following example, a function return user with both Promise or async/await style.
if we use Promise:
function getFirstUser() {
return getUsers().then(function(users) {
return users[0].name;
}).catch(function(err) {
return {
name: 'default user'
};
});
}
if we use aysnc/await
async function getFirstUser() {
try {
let users = await getUsers();
return users[0].name;
} catch (err) {
return {
name: 'default user'
};
}
}
Here in promise approach we need a thenable structure to follow and in async/await approach we use 'await' to hold execution of asynchronous function.
you can checkout this link for more clarity Visit https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8

Yesterday I made a tentative decision to switch from using Promises to using Async/Await, independent of nodejs, based on the difficulty in accessing previous values in the Promise chain. I did come up with a compact solution using 'bind' to save values inside the 'then' functions, but Async seemed much nicer (and it was) in allowing direct access to local variables and arguments. And the more obvious advantage of Async/Await is, of course, the elimination of the distracting explicit 'then' functions in favor of a linear notation that looks much like ordinary function calls.
However, my reading today uncovered problems with Async/Await, which derail my decision. I think I'll stick with Promises (possibly using a macro preprocessor to make the 'then' functions look simpler) until Async/Await gets fixed, a few years from now.
Here are the problems I found. I'd love to find out that I am wrong, that these have easy solutions.
Requires an outer try/catch or a final Promise.catch(), otherwise errors and exceptions are lost.
A final await requires either a Promise.then() or an extra outer async function.
Iteration can only be properly done with for/of, not with other iterators.
Await can only wait for only one Promise at a time, not parallel Promises like Promise chains with Promise.all.
Await doesn't support Promise.race(), should it be needed.

Related

Promise.allSettled rewrite in async await

I got a piece of code that would submit several set of reports which they are independent each other, currently wrote in promise.allSettled, but I was told that the team standard would require async await instead of promise
"Never use multiple await for two or more independent async parallel tasks, because you will not be able to handle errors correctly. Always use Promise.all() for this use case."
1
"In comparison, the Promise returned by Promise.all() may be more appropriate if the tasks are dependent on each other / if you'd like to immediately reject upon any of them rejecting."
2
"Using for await...of, you have more granular control of the promises. So if the order in which promises complete is important to you, for await...of is your preferred choice. However, the increased control isn’t free. The fact that for await...of handles promises one by one, makes it a lot slower."
"To sum up, the three methods are all capable of handling iterables of promises, but differ slightly in their functioning. Use for await of if the order in which promises are resolved is important to you. Use Promise.all() if the order isn’t important and you need all calls to succeed. Use Promise.allSettled() if the order isn’t important and you don’t absolutely need all individual calls to be successful."
3
After some research, I found it is not possible to rewrite it in async await with the same efficiency (request execute in parallel) and simplicity (promise.allSettled is a built-in function), am I correct?
That piece of code
const recordInsertErrors:Object[] = [];
await Promise.allSettled(
jsonArray.map((eachPositionReport) => {
return PositionReport.query().insert(eachPositionReport).catch((err) => {
const error = { vessel_ownership_id: eachPositionReport.vessel_ownership_id, error: err.nativeError };
recordInsertErrors.push(error);
throw err;
});
}),
);
First of all JavaScript code does not run in parallel. The most we can say is that it executes asynchronously, i.e. it gets executed by the engine while monitoring its job queues. The "only" thing that might execute in parallel is lower-level, non-JavaScript logic, such as provided by some APIs that make asynchronous HTTP requests.
Secondly, whether an asynchronous operation starts while another is still underway, is not determined by the use of Promise.all, Promise.allSettled, for await ... of, ...etc, but by whether or not all involved promises are created immediately or not. That is part of the code that is not orchestrated by any of the mentioned constructs.
So surely you can use async and await keywords to achieve that asynchronous requests are made without waiting that a previous one has completed.
For instance:
const recordInsertErrors = [];
const promises = jsonArray.map(async (eachPositionReport) => {
let value;
try {
value = await PositionReport.query().insert(eachPositionReport);
} catch(err) {
value = {
vessel_ownership_id: eachPositionReport.vessel_ownership_id,
error: err.nativeError
};
}
return value;
});
// All promises will now fulfill, as errors are converted to
// fulfillments with an error property
(async () => {
for (const promise of promises) {
const value = await promise;
if (value.error) recordInsertErrors.push(value);
console.log(value);
}
})();
The for loop with await expressions will not delay the moment at which all promises have resolved. It will potentially report sooner on some results than Promise.allSettled, as the latter is designed to first wait until all promises have settled, and only then resolve its own promise.

Use promise-returning code without async/await

I'm trying to quickly write a simple tool in NodeJS using pdf-lib. pdf-lib appears to be designed to use promises and async/await, but I don't want the extra code complexity of async/await for such a simple tool.
How can I use functions that return a promise without the extra bother of async/await?
Since the library primarily uses Promises, you will have to learn how to use Promises regardless, if you want to be able to use the library.
If you think async/await will be too difficult, you can construct .then chains instead. When you start with a Promise or have a Promise inside a .then, make another .then, whose callback will run when the Promise resolves. For example, this:
const pdfDoc = await PDFDocument.load(existingPdfBytes)
// Embed the Helvetica font
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
if you want to do away with async/await, can be
// first Promise
PDFDocument.load(existingPdfBytes)
.then((pdfDoc) => {
// second Promise: return it so its resolve value can be used in the next `.then`
return pdfDoc.embedFont(StandardFonts.Helvetica);
})
.then((helveticaFont) => {
// helveticaFont is now available inside this `.then`
})
.catch(handleErrors); // don't forget this
Or you could nest the second .then inside to have access both to pdfDoc and helveticaFont at once, or use Promise.all:
PDFDocument.load(existingPdfBytes)
.then((pdfDoc) => {
return pdfDoc.embedFont(StandardFonts.Helvetica)
.then((helveticaFont) => {
// both helveticaFont and are available inside this `.then`
});
})
.catch(handleErrors);
or
const pdfDoc = await
// first Promise
PDFDocument.load(existingPdfBytes)
.then((pdfDoc) => {
return Promise.all([pdfDoc.embedFont(StandardFonts.Helvetica), pdfDoc]);
})
.then(([helveticaFont, pdfDoc]) => {
// both helveticaFont and are available inside this `.then`
})
.catch(handleErrors);
But, as you can see, it gets really messy when you have lots of asynchronous requests to make. I'd highly recommend using async/await here if at all possible - it'll make things much easier and much less complicated. On the contrary, deliberately avoiding async/await will probably make things significantly (and unnecessarily) more tedious.

How to avoid indented nested promises?

I heard that promises are supposed to be linear in code in opposed to callbacks ("callback hell").
Though I still have a scenario similar to callback hell and hoping promises can make their promise and have a linear syntax equivalent to this problem code.
Given promises p(), q(),w() consider this code:
p().then(() => {
q().then(() => {
w().then(() => {
// do something
})
})
})
Can we make an equivalent code which is not indented for every nested promise?
You should not nest the .then() handlers but let each .then() create and return a new Promise. This is how it was designed to work, otherwise you are still in the callback hell, now the version with promises. No big difference.
The code should be like this:
p()
.then(() => {
return q();
})
.then(() => {
return w();
})
.then(() => {
// do something
});
If all that the .then() handlers do is to call the next function you can write it in a simpler form (read about arrow functions):
p()
.then(() => q())
.then(() => w())
.then(() => {
// do something
});
Even more, if q and w are called without arguments, the code could be as simple as:
p()
.then(q)
.then(w)
.then(() => {
// do something
});
Or you can go the extra mile and instead of using .then() and .catch() you use await. The code becomes even more clear and easy to read:
try {
await p();
await q();
await w();
// do something
} catch (err) {
// write here the code you would write in the handler you pass to `.catch()
// in the approach that uses Promises
}
Remarks
If the code above, using await, is used in a function then that function must be an async function (just put async in front of its definition).
The code that uses await may or may not be used outside of a function (i.e. at module's top level) depending on the runtime you use to run it (browser, Node.js etc).
As another user mentioned, you could use async/await but another option is just to slightly restructure what you have. Here are some examples of what could work – depending on where and when you need certain pieces of data:
p()
.then(q)
.then(w)
// OR
p()
.then(() => q())
.then(() => w())
Obviously this gets a little more complicated if w() needs data from both p() and q() but that's the gist of it.
You could try using async/await, which leaves a more cleaner code. It would be like this:
(async () => {
try {
await p();
await q();
await w();
} catch (e) {
// handle error
}
})()
If there is no dependency between each promise you can use await Promise.all in order to do "all or nothing". In any other case, you can store the returned value and pass it to the next function in order to be used if needed.

Explain me like I'm 5 - ES6 Promises & async/await differences and is my code "right"?

I'm having difficulties understanding ES6 Promises and Async/await.
I looked up for videos on youtube explaining those topics and still my head cannot sink inm what is the difference between them and when should I use Promises over Async/await or Async/await over Promises?
Also when do I know if my code is "valid" promises or async/await.
Here I have two examples (both working) that fetches "companies" from my local JSON server and when it's finished, it loops through those companies.
First example: ( Using Promises )
function getCompanies() {
return new Promise((resolve, reject) => {
fetch(`http://localhost:3000/companies`)
.then(response => response.json())
.then(response => resolve(response))
.catch(error => reject(error))
})
}
function loopCompanies(companies) {
companies.forEach((company) => {
console.log(company);
})
}
getCompanies().then(response => loopCompanies(response)).catch(error => console.log(error));
Second Example: (Using Async/await)
async function getCompanies() {
let response = await fetch(`http://localhost:3000/companies`);
let processedResponse = await response.json();
return processedResponse
}
function loopCompanies(companies) {
companies.forEach((company) => {
console.log(company);
})
}
async function doIt() {
try{
let response = await getCompanies();
loopCompanies(response)
} catch(error) {
console.log(error)
}
}
doIt()
So I wan't know if that's how I should use Promises in Example 1?
Is that how I should use Async/await in Example 2 ?
And what are the differences between them
The first example is unnecessarily wrapping a manually created promise around a promise you already have. This is an anti-pattern for a variety of reasons. You should just return the promise that fetch() already returns. You can do this:
function getCompanies() {
return fetch(`http://localhost:3000/companies`)
.then(response => response.json());
})
}
function loopCompanies(companies) {
companies.forEach((company) => {
console.log(company);
})
}
getCompanies().then(response => loopCompanies(response)).catch(error => console.log(error));
The second example (using async/await) looks fine to me. You can simplify it a bit by changing this:
async function getCompanies() {
let response = await fetch(`http://localhost:3000/companies`);
let processedResponse = await response.json();
return processedResponse
}
to this:
async function getCompanies() {
let response = await fetch(`http://localhost:3000/companies`);
return response.json();
}
As there is no need to await a value you are just going to return. Instead, you can just return the promise directly. Either generates the same result, but the second way does it with less code.
I looked up for videos on youtube explaining those topics and still my head cannot sink inm what is the difference between them and when should I use Promises over Async/await or Async/await over Promises?
async and await absolutely use promises. In fact, await does nothing useful unless you await a promise. And, async functions ALWAYS return a promise. So, async/await are not an alternative to promises. They are an alternative to .then() that gives you a different syntax that is sometimes more friendly to write, debug and read, particularly when you want to sequence multiple asynchronous operations.
Also when do I know if my code is "valid" promises or async/await.
Your code is valid when it delivers the proper result in both success and error conditions and is written without unnecessary steps and without anti-patterns. There's no magic answer beyond that. There is no tool I'm aware of that will tell you that. Just like there's no tool that will tell you if you're 100 line function is written well or not. You have to learn good coding practices for Javascript asynchronous development and then you will recognize good patterns and not-so-good patterns.
So I wan't know if that's how I should use Promises in Example 1?
See my fixed up example above for removing the anti-pattern from Example 1.
Is that how I should use Async/await in Example 2 ?
Yes, that's fine, but it can be simplified further as I showed in my example above.
And what are the differences between them
In my two amended examples, they accomplish the same result. They are just two different coding styles. You can decide which one you prefer. Neither is "more right" than the other.
My personal style is to use async/await when there's a good reason to use it such as:
Multiple asynchronous operations I'm sequencing.
When it leads to simpler, foolproof error handling.
When it leads to simpler looking code.
When I want to make sure synchronous exceptions get caught and turned into a rejected promise.
When I don't need to run in older JS engines that might not support async/await without transpiling.

Async / await vs then which is the best for performance?

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.
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.
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).");
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.
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
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.
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.
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
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);
});
}

Categories