I have code in Javascript that looks like this:
function someFunction() {
// Code
somePromise().catch(err => {
console.log(err);
});
// Mode Code
}
I would like to escape both somePromise().catch and someFunction() in the event that somePromise() is rejected. I tried using return but that only allows me to escape somePromise().catch. Is there any function that would allow me to break out of nested loops?
You can do that by using async/await:
function async someFunction() {
// Code
try {
await somePromise();
} catch (err) {
console.log(err);
return; // aborts further execution
}
// More Code
}
See async function for details.
Async/await solves the problem but it's important to understand why it solves the problem.
Promises are a mechanism for storing continuations. Functions you pass to then and catch are stored within the promise and are executed when the promise is resolved.
To solve this without async/await, you would simply return the Promise and use then to execute any code that should execute when the Promise does not reject:
function someFunction() {
// Code
return somePromise()
.then(result => {
// More Code
})
.catch(err => {
console.log(err);
});
}
This is essentially what async/await de-sugars to. Async/await is syntactic sugar around a state machine that wires up these continuations for you.
Related
In the below code have I createPost() inside an async function, but I don't want to use await on it, so it blocks execution of the rest of the function. That is why I used then.
The outer async function have lots of other functions that use await, so that can't be changed.
Question
Since createPost() is a async/await function (see below). How can it resolve/reject to then/catch in the outer function?
module.exports = async (p) => {
// lots of code here
const t = await function1();
// lots of code here
createPost(p).then(message => {
// lots of code here
console.log("ok " + message);
}).catch(message => {
console.log("failed " + message);
});
};
createPost()
module.exports = async (p) => {
// lots of code here
try {
const r = await getStat();
} catch (error) {
console.log(error);
};
};
async / await is a more modern equivilant to .then / .catch.
In this case you have mixed the syntaxes of both.
You don't need try / catch blocks when using .then,
just like you don't need to declare a function as async when using the try / catch syntax.
Other than that there's no reason they can't work together in seperate functions.
module.exports = (p) => {
createPost(p).then(message => {
console.log("ok " + message);
}).catch(message => {
console.log("failed " + message);
});
};
createPost():
module.exports = async (p) => {
try {
const r = await getStat();
} catch (error) {
console.log(error);
};
};
An async decleration on a function is redundant and wrong if you're not using the await keyword inside.
await/async are often referred to as syntactic sugar, and let us wait for something (e.g. an API call), giving us the illusion that it is synchronous in an actual asynchronous code, which is a great benefit.
The things you want to acheive with async/await is is possible with promises but the advantages of async/await. let's an example with this code:
const makeRequest = () => //promise way
getJSON()
.then(data => {
return data
})
makeRequest();
const makeRequest = async () => { //async await way
const data = await getJSON();
return data;
}
makeRequest()
Why is async/await prefered over promise?
Concise and clean - We didn’t have to write .then and create an anonymous function to handle the response, or give a name data to a variable that we don’t need to use. We also avoided nesting our code. async/await is a lot cleaner.
Error handling - Async/await makes it finally possible to handle both synchronous and asynchronous errors with the same try/catch format.
Debugging - A really good advantage when using async/await is that it’s much easier to debug then promises for 2 reasons: 1) you can’t set breakpoints in arrow functions that return expressions (no body). 2) if you set a breakpoint inside a .then block and use debug shortcuts like step-over, the debugger will not move to the the following .then because it only “steps” through synchronous code.
Error stacks - The error stack returned from promises chain gives us no idea of where the error occured and can be misleading. async/await gives us the error stack from async/await points to the function that contains the error which is a really big advantage.
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.
While I thought I was using Async and Await keywords properly, it appears as though I am doing something wrong.
I am using PouchDB, which is a great Javascript database that syncs with CouchDB. PouchDB uses promises for many of its functions, and has native support for Async and Await. As an example, to retrieve the basic information about a database, you would use the following code:
db.info().then(function (info) {
console.log(info);
})
I understand this, and it works. But if I try and put this inside a function, and then call that function, things go haywire. And I'm sure it's me and not PouchDB that is the problem...
function getLocalDBInfo(db){
try {
db.info().then(function (info) {
return info;
});
} catch (error) {
console.log("can't get local DB info: ", error);
}
}
async function testing(db){
try {
var info=await getLocalDBInfo(db);
await console.log("DB info=", info);
await console.log("Doc count= ", info.doc_count);
}
catch(err){
console.log("error=",err);
}
//info contains...
//{"doc_count":0,"update_seq":0,"db_name":"kittens"}
}
testing(MY_db);
If I log info inside the getLocalDBInfo function, it eventually (ie. after the promise fulfills) logs info to the console. But, the logs inside the testing function return immediately with undefined. It makes sense to me that they are returning undefined because they are returning immediately, but I was trying to have them wait for info by using async and await. Any suggestions as to what I am doing wrong?
getLocalDBInfo() is not returning a promise, so you can't await for it.
with async/await you could:
async function getLocalDBInfo(db){
try{
return await db.info()
} catch (err){
console.log("can't get local DB info: ", error);
}
}
you can also use new promise
getLocalDBInfo generates a promise, attaches a callback to it, then returns undefined. It doesn't return the resolved promise and you can't await on an undefined (well, you can, but it won't do anything).
You neee to change getLocalDBInfo to actually return the promise.
Also, why do you have a then block with the signature info => info? All this will do is unwrap the async value and then wrap it again. You can omit the then callback entirely.
Similarly, are you sure you need to wrap the db.info call in a try/catch? I wonder if you might be intending to use a promise.catch here instead. The try/catch construct only grabs promise rejections when awaiting an expression.
You need to return the value from the outer function getLocalDBInfo
function getLocalDBInfo(db) {
return new Promise((resolve, reject) => {
db.info()
.then(info => resolve(info))
.catch(err => reject(err))
})
}
As outlined by this SO post and answer, it is customary to throw an error from the catch statement that resides inside an async/await function like so:
} catch (error) {
throw new Error(400);
}
As highlighted by that same post, you typically wouldn't return a rejected promise (see below) since it's a semantic mis-match with 'try-catch' statements.
} catch (error) {
return Promise.reject(new Error(400));
}
By that same logic, should I be returning rejected promises when returning errors outside of catch statements from my async/await function instead of throwing them?
In other words is the following semantically inconsistent with the above logic?
async function promise () {
throw new Error('Some error');
}
And, is this the preferred way of returning an error inside an async/await function since async/await functions implicitly return a promise?
async function promise () {
return Promise.reject(new Error(400));
}
I'm aware both of the above snippets allow errors to be caught when consuming the promise.
You generally use throw where you can, i.e. in async functions or then callbacks, because it is simpler and therefore easier to read. return Promise.reject(…) does work but is lengthy.
I am working on a simple TCP client for a server and am using the latest node 7.6 because of the async/await functions. I'm new to node and asynchronous coding, so I apologize if this is stupidly easy.
I want to run a function that calls the callServer() function with specific parameters, wait until it finishes getting the data, and return the data as a variable.
Here is my code:
'use strict'
const net = require('net')
var formattedJson = funcRequestToJson("Server.GetStatus", false)
doThings()
async function doThings() {
var info = await callServer()
}
async function callServer() {
var client = new net.Socket()
client.connect(1705, '192.168.28.16', () => {
console.log('connected to server')
client.write(formattedJson)
})
client.on('data', (data) => {
client.destroy()
//return await data
console.log(data.toString())
})
client.on('close', () => {
})
}
// method and paramBool are always required
// macAddress, paramKey, paramValue are required for if paramBool is true
function funcRequestToJson(method, paramBool, macAddress, paramKey, paramValue) {
var objectRequest = {}
objectRequest[ "jsonrpc" ] = "2.0"
objectRequest[ "method" ] = method
objectRequest[ "id" ] = 0
if (paramBool == true) {
objectRequest[ "params" ] = {
"client": macAddress,
[paramKey]: paramValue
}
}
var json = (JSON.stringify(objectRequest) + '\r\n')
return json
}
So I didn't declare objectRequest() as async because it's not waiting on the server, but I think callServer() should be async, right? I know this can be done with promises, but I wanted to use async/await and this seems to be right.
Now, I want to return the data that comes from inside callServer() and client.on('data', (data) but I can't seem to figure out how to do it asynchronously. I would think there'd be a way to make an async function and call it with await like I tried (await return data) but it never works right.
I'm sorry if this is terribly convoluted, but I've been poring over async node tutorials for the past week and am still stuck.
Thanks!
Async/Await relies on code that uses promises for async operations. So you need to return a promise from any async operation in order to use it with async/await.
So, callServer() needs to return a promise that is resolved when the async operation inside it is done. In fact, you can only await an async operation in a function if that function returns a promise. await saves you from having to write .then() handlers on promises, but async/await does not magically know when async operations are done. You still have to wrap them in promises.
Here's an example of how you could make callServer() return a promise:
async function callServer(formattedJson) {
return new Promise((resolve, reject) => {
let client = new net.Socket()
client.connect(1705, '192.168.28.16', () => {
console.log('connected to server')
client.write(formattedJson)
})
client.on('data', (data) => {
resolve(data);
client.destroy()
})
client.on('close', () => {
})
client.on('error', reject);
});
}
Sample Usage:
try {
var info = await callServer(funcRequestToJson("Server.GetStatus", false));
} catch(e) {
// error here
}
Just to show you what await is doing, in ES5 (without async/await), the sample usage would be this:
callServer(funcRequestToJson("Server.GetStatus", false)).then(info => {
// info is available here
}).catch(err => {
// error here
});
So, await is just letting you avoid writing the .then() handler. Internally in the execution of the code, there's just a promise that the interpreter sets up a .then() handler for so it will know when that promise is resolved. This is syntactical sugar, not really any magic with async operations. You still have to use promises for all your async operations. You can use await instead of .then() and your code will appear more sequential even though it's really the same under the covers.
People think that await allows one to write asynchronous code as if it was synchronous, but that isn't really the case, especially if you handle errors and understand concurrency issues. It will look more synchronous, but isn't actually any more synchronous than it was with .then() in ES5.
And, watch out for error handling. In people's quest to write synchronous looking code, people seem to completely forget to handle rejected promises in their async operations (which are handled with try/catch when using await). I'm personally not yet convinced that ES6 is a step forward when it comes to error handling as the early indications are that ES6 seems to encourage people to just forget about error handling or get lazy and not do it, whereas it's easier when using .then() to just know that there should be a .catch() somewhere for it to be solid code. Maybe that's just a learning process, but it seems to be an early issue when people use await.