Async Await Behaviour - node.js

A simple code to understand async/await is making me crazy.
I have a button on click on which i am reading some value from localstorage and showing it in an alert box. Before showing the alert i want to console.log the value.
If i understood async/await my code should d exactly that but it is working in reverse order. first the alert is coming and then the console.
//Method called on button click
findMyAge2() {
this.getData("age").then(result => {
console.log('Hi');
myAge2 = result;
});
alert(myAge2);
}
async getData(key): Promise<any> {
return await this.storage.get(`${key}`);
}
Expected Result:
in Console log :Hi
UI: Age
Actual Results:
UI: Age
in Console log :Hi

JavaScript is asynchronous by nature, so when you have a Promise returned, code continues execution and that Promise resolves some time afterward.
async/await is a way to control this flow of programming and can allow you to create Synchronous code that "awaits" the result of asynchronous execution.
Your problem here is that you want to return the promise from your getData function and await it in your findMyAge2 function.
async function findMyAge2() {
let result = await this.getData("age");
console.log('Hi');
myAge2 = result;
alert(myAge2);
}
async getData(key): Promise<any> {
return this.storage.get(`${key}`);
}
By adding async keyword to a function it will always now return a Promise. So you do not need to await in your return statement. That effectively does nothing. It would be like saying:
function getData(key) {
return new Promise(resolve => {
return localStorage.get(`${key}`).then(result => resolve(result))
})
}
You don't need to await that result in local storage because the consumer should be calling await or .then on the result regardless.

Try this way,
findMyAge2() {
this.getData("age").then(result => {
console.log('Hi');
myAge2 = result;
alert(myAge2);
});
}
async getData(key): Promise<any> {
return await this.storage.get(`${key}`);
}
Before you should wait to alert before data being retrieved.

async/await works like with promises, which means, code gets executed and you don't know when it will finish, you just know that after if finishes, you want something else to be executed.
This is exactly what you put inside the "then" function, which is what gets executed after the 1st part (asyc getData) gets executed.
In the case of your code, the findMyAge2 gets called when you click the button, then it executes the getData and specifies what happens after getting the result from that call, within the "then" block.
Therefore you just have to move the alert, into "then" block, then you'll have the result you expect.
var myAge2;
findMyAge2() {
this.getData("age").then(result => {
console.log('Hi');
myAge2 = result;
alert(myAge2);
});
}
async getData(key): Promise<any> {
return await this.storage.get(`${key}`);
}

Related

What is Async in Nodejs

If I am trying to write an app.post() function why do some examples use async and some just writes a regular function(req,res)? What does async do that is different from regular function?
async (Asynchronous) function gives your code the ability to pause for any action. Let's see some examples:
SamplePost = (data) => {
let result;
result = Request.Send("POST", data);
console.log(result);
}
If you run the above function with an actual POST request It'll print null because by the time the result of the request will be fetched the console.log will finish executing.
SamplePost = async (data) => {
let result;
result = await Request.Send("POST", data);
console.log(result);
}
But in the above code it will print the actual result. Because this time the code will pause at the async and as long as it doesn't return any value (Not a Promise) it'll keep waiting and as soon as it'll get a return value it'll continue the code.
Sorry in advance for overcomplicating

How to stop BrowserWindow from breaking after a single error in executeJavaScript?

I'm using the executeJavaScript method to control a page via Electron. However, I've noticed that the BrowserWindow instance essentially becomes unresponsive after one error occurs. Aside from putting every single line of code in a try/catch block, is it possible to disable this functionality?
Specifically, I'd prefer that the BrowserWindow continues to execute future code despite running into an error on a previous request. For example, in the code below, I want the console to successfully output I'm not being executed.
const {BrowserWindow, app} = require('electron')
async function main() {
var win = new BrowserWindow({webPreferences: {nodeIntegration: false} });
win.openDevTools();
win.loadURL('https://www.homedepot.com');
await sleep(10000); //letting page load
await win.webContents.executeJavaScript('console.log("Im being executed")')
await sleep(2000);//break
await win.webContents.executeJavaScript('undefinedVar.causeError()')
await sleep(2000);//break
await win.webContents.executeJavaScript('console.log("Im not being executed")')
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
app.on('ready', main)
First, I don't believe the BrowserWindow is unresponsive after executing the broken code. You can still move it around and maximize it, etc. It's just that the Promise returned by executeJavaScript is stuck in a pending state, and so you never finish awaiting it.
This is actually fixed in Electron 6 by this pull request. In Electron 6, you can do this:
var win;
async function createWindow2() {
win = new BrowserWindow();
win.openDevTools();
await win.loadURL('https://www.google.com');
await executeSafely('console.log("Im being executed")');
await executeSafely('undefinedVar.causeError()');
await executeSafely('console.log("Im not being executed")');
}
async function executeSafely(code) {
try {
await win.webContents.executeJavaScript(code);
}
catch (e) { } // assuming you want to ignore errors
}
If upgrading Electron isn't an option for you, then you can create a function that wraps your code in a Promise, or a try/catch depending on what you need.
If you just want to ignore all errors, then wrapping your executed-code in a try/catch is sufficient. Otherwise, you can wrap in a Promise, which should result in the Promise returned by executeJavaScript being rejected. Example:
async function main() {
var win = new BrowserWindow();
win.openDevTools();
win.loadURL('https://www.google.com');
await sleep(5000);
await win.webContents.executeJavaScript(makeSafe('console.log("Im being executed")'));
await win.webContents.executeJavaScript(makeSafe('undefinedVar.causeError()'));
await win.webContents.executeJavaScript(makeSafe('console.log("Im not being executed")'));
}
function makeSafe(code) {
return "try{" + code + "}catch{}";
}

How to do proper error handling with async/await

I'm writing an API where I'm having a bit of trouble with the error handling. What I'm unsure about is whether the first code snippet is sufficient or if I should mix it with promises as in the second code snippet. Any help would be much appreciated!
try {
var decoded = jwt.verify(req.params.token, config.keys.secret);
var user = await models.user.findById(decoded.userId);
user.active = true;
await user.save();
res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
next(error);
}
Second code snippet:
try {
var decoded = jwt.verify(req.params.token, config.keys.secret);
var user = models.user.findById(decoded.userId).then(() => {
}).catch((error) => {
});
user.active = true;
await user.save().then(() => {
}).catch((error) => {
})
res.status(201).json({user, 'stuff': decoded.jti});
} catch (error) {
next(error);
}
The answer is: it depends.
Catch every error
Makes sense if you want to react differently on every error.
e.g.:
try {
let decoded;
try {
decoded = jwt.verify(req.params.token, config.keys.secret);
} catch (error) {
return response
.status(401)
.json({ error: 'Unauthorized..' });
}
...
However, the code can get quite messy, and you'd want to split the error handling a bit differently (e.g.: do the JWT validation on some pre request hook and allow only valid requests to the handlers and/or do the findById and save part in a service, and throw once per operation).
You might want to throw a 404 if no entity was found with the given ID.
Catch all at once
If you want to react in the same way if a) or b) or c) goes wrong, then the first example looks just fine.
a) var decoded = jwt.verify(req.params.token, config.keys.secret);
b) var user = await models.user.findById(decoded.userId);
user.active = true;
c) await user.save();
res.status(201).json({user, 'stuff': decoded.jti});
I read some articles that suggested the need of a try/catch block for each request. Is there any truth to that?
No, that is not required. try/catch with await works conceptually like try/catch works with regular synchronous exceptions. If you just want to handle all errors in one place and want all your code to just abort to one error handler no matter where the error occurs and don't need to catch one specific error so you can do something special for that particular error, then a single try/catch is all you need.
But, if you need to handle one particular error specifically, perhaps even allowing the rest of the code to continue, then you may need a more local error handler which can be either a local try/catch or a .catch() on the local asynchronous operation that returns a promise.
or if I should mix it with promises as in the second code snippet.
The phrasing of this suggests that you may not quite understand what is going on with await because promises are involved in both your code blocks.
In both your code blocks models.user.findById(decoded.userId); returns a promise. You have two ways you can use that promise.
You can use await with it to "pause" the internal execution of the function until that promise resolves or rejects.
You can use .then() or .catch() to see when the promise resolves or rejects.
Both are using the promise returns from your models.user.findById(decoded.userId); function call. So, your phrasing would have been better to say "or if I should use a local .catch() handler on a specific promise rather than catching all the rejections in one place.
Doing this:
// skip second async operation if there's an error in the first one
async function someFunc() {
try {
let a = await someFunc():
let b = await someFunc2(a);
return b + something;
} catch(e) {
return "";
}
}
Is analogous to chaining your promise with one .catch() handler at the end:
// skip second async operation if there's an error in the first one
function someFunc() {
return someFunc().then(someFunc2).catch(e => "");
}
No matter which async function rejects, the same error handler is applied. If the first one rejects, the second one is not executed as flow goes directly to the error handler. This is perfectly fine IF that's how you want the flow to go when there's an error in the first asynchronous operation.
But, suppose you wanted an error in the first function to be turned into a default value so that the second asynchronous operation is always executed. Then, this flow of control would not be able to accomplish that. Instead, you'd have to capture the first error right at the source so you could supply the default value and continue processing with the second asynchronous operation:
// always run second async operation, supply default value if error in the first
async function someFunc() {
let a;
try {
a = await someFunc():
} catch(e) {
a = myDefaultValue;
}
try {
let b = await someFunc2(a);
return b + something;
} catch(e) {
return "";
}
}
Is analogous to chaining your promise with one .catch() handler at the end:
// always run second async operation, supply default value if error in the first
function someFunc() {
return someFunc()
.catch(err => myDefaultValue)
.then(someFunc2)
.catch(e => "");
}
Note: This is an example that never rejects the promise that someFunc() returns, but rather supplies a default value (empty string in this example) rather than reject to show you the different ways of handling errors in this function. That is certainly not required. In many cases, just returning the rejected promise is the right thing and that caller can then decide what to do with the rejection error.

Why does await function return pending promise

let request = require('request-promise')
function get(url) {
let _opt = {}
let response = (async () => {
try {
var ret = await request(url, _opt);
return ret;
} catch (e) {
console.log(e)
}
})();
return response
}
console.log(get('http://www.httpbin.org/ip'))
gives:
Promise { <pending> }
Why doesn't it wait for my response?
Why doesn't it wait for my response?
That's simple, because you are returning a promise. Node js is single thread and is executed in a non blocking way.
That means that return response in your get function is executed before the resolution of response variable.
Try as follow:
let request = require('request-promise')
function get(url) {
let _opt = {}
return request(url, _opt);
}
async function some () {
console.log(await get('http://www.httpbin.org/ip'));
}
some();
This example is also returning a promise, but in this case we are awaiting for the promise resolution.
Hope this help.
Async functions are non-blocking and will immediately return a promise rather than waiting for a result. This for example, allows for multiple async functions to run concurrently rather than each running sequentially.
To wait for a result, you can use the await keyword to block until the promise is resolved. The await command will return the result of the promise. For example, to log the result of the get function, you can change the last line to:
console.log(await get('http://www.httpbin.org/ip'))
UPDATE:
Let me give this one more try (sorry if I'm beating a dead horse here).
Since your response variable is an async function, it's return type is a promise by the definition of an async function. Even though the ret variable is await'ed, that just means that it will block while writing to the ret variable. The response async function needs to be run to completion in order for the await to complete. An await here would be useful if you wanted to wait for the return value and then add post-processing, but in this example specifically, your try block could simply be:
try {
return request(url, _opt)
}
Since request already returns a promise, the extra await is causing a trivial amount of overhead since it implicitly creates an extra promise.
Since response is a promise, and you are returning response, the function get is also returning a promise. You are then trying to log this promise (which obviously doesn't work). This is why you must await or .then the get function to get the result.
Source: https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8 under "Pitfall 1: not awaiting"

Why I need to call every function with async keyword for calling an API in modularized code

I have just started with async and await and trying to convert all my callback syntax to async/await style.
One thing I could not understand is, why I need to every time prefix my function with async keyword.
Here is the example:
APIQuery.js
makeRequest: async(options) => {
try {
var response = await(request(options1))
}
catch(err){
console.log("Some error occurred");
response = undefined;
}
return response;
}
MobileAPI.js
getMobileData: async modal => {
var options = {method: 'GET', json: true,uri: 'https://example.com/mobile/'+modal}
var response = await APIQuery.makeRequest(options);
}
MobileService.js
getMobileDataService: async modal => {
var response = await MobileAPI.getMobileData(modal);
}
MobileController.js
Similarly again I have to use async and await combination to return response.
So my question is, is there a way to get rid of using this everywhere. Calling async await inside APIQuery.js is not enough?
If you want to use the await operator, you have to use async keyword before function declaration:
The await operator is used to wait for a Promise. It can only be used inside an async function.
If you don't want to use async everywhere, you can continue using callbacks or Promises (then, catch, etc.).
So my question is, is there a way to get rid of using this everywhere.
You can't block. Period. As soon as you block, your server would become completely unresponsive to all requests until it's unblocked. For this reason, your code must be asynchronous.
Callbacks are a perfectly valid form of asynchrony, but async/await is easier to use, understand, and maintain.

Resources