Await for a function to finish not working - javascript

I have the first function that looks like this:
private async checkIsExists(): Promise<Boolean> {
this.repositoryService.getEntry(this.id)
.subscribe({
error: (err) => {
return false;
}
});
return true;
This function should return false if any error occurs, such as a 404.
In the repositoryService i have the getEntry function that looks like this:
getEntry(entryId: string) {
return this.collectionsApi.getEntry(entryId);
}
Which is not an async function
My question would be, how could i make the check function work correctly, at this moment it returns true no matter what, because it doesnt wait for the data to be fetched, i would like to change only this function if possible
Update:
I changed the function and the call to this:
private checkIfShareExists(): Observable<Boolean> {
return this.repositoryService.getEntry(this.id).pipe(
catchError(() => of(false)),
map( () => {
return true;
})
)}
...
this.checkIfShareExists().subscribe(exists => {
console.log(exists);
});
But it still prints true always, even though the error is thrown

Assuming getEntry is an observable (since you are subscribeing to it) you can use async await if you transform it into a promise:
private async checkIsExists(): Promise<Boolean> {
return await this.repositoryService.getEntry(this.id).toPromise().then(r => true).catch(r => false);
}
After this you can use that function inside another async-await block to get your boolean result:
async myFunc(){
var couldGet = await this.myComponent.checkIsExist();
if(!couldGet) { console.error("sadface.jpg") }
}

Related

Promise, async, await - Boolean returns false but if condition still gets called

Context
I have this piece of code to force app update, that checks whether an update is needed and is supposed to return true or false depending on the version number of the user's app vs the App Store version. This seems to be working correctly when the version number of the user's app is lower, because it stores the right url in the website variable:
let website = ''
const isLatestVersion = async (): Promise<boolean> => {
await VersionCheck.needUpdate({
packageName: 'com.tfp.numberbomb',
}).then((res) => {
if (res.isNeeded) {
website = res.storeUrl
return true // open store if update is needed.
} else return false
})
}
Problem
It doesn't work correctly when the version number of the user's app is equal/higher. This is the function where I am using the function from above. For some reason, the logic executes showPopup() even if the response from the function is false. What am I doing wrong?:
const handleBiometricLogin = async () => {
if (!(await isLatestVersion())) {
await showPopup()
return
}
... // rest of the logic that doesn't run even when it's supposed to because of the return statement
Additional info
showPopup() function just for reference:
const showPopup = async () => {
Alert.alert(
translations['errors.login.update.title'] ?? 'Download Available',
translations['errors.login.update.body'] ??
'There is a new download available on the app store. Please update to gain access',
[
{ text: translations['form.no-answer'] ?? 'No' },
{
text: translations['form.yes-answer'] ?? 'Yes',
onPress: () => handleOpenLink(website, translations),
},
],
)
}
I feel like I am doing the async and await stuff correctly, and I tried to search for possible duplicates but it's difficult to find anything
I wonder how TypeScript hasn't caught this, but the problem is that your function returns a Promise<void> instead of a Promise<boolean>. You never return anything from isLatestVersion, so it ends up with undefined, and your inverted condition always runs the if block.
The underlying issue is with awaiting a .then(…) chain - you want to use either then and return:
const isLatestVersion = (): Promise<boolean> => {
// ^ no async
return VersionCheck.needUpdate({
//^^^^^^
packageName: 'com.greenshield.mobileclaims',
}).then((res) => {
console.log(res)
return res.isNeeded
})
}
or only await:
const isLatestVersion = async (): Promise<boolean> => {
const res = await VersionCheck.needUpdate({
// ^^^^^
packageName: 'com.greenshield.mobileclaims',
});
// ^ no .then()
console.log(res)
return res.isNeeded
}

Function returns before completing her job

I've written this function, and it returns the values, before doing her job. So the return is allways undefined. How can I get the right results?
The code:
async function isReachable(hostname, port) {
net
.connect(port, hostname, () => {
console.log(true);
return true;
})
.on('error', () => {
console.log(false);
return false;
});
}
The log:
Promise { undefined }
true
Thank you :)
Change the start of your method to this:
async function isReachable(hostname, port) {
return net
.connect(
...
You're missing the return, and you're getting the default undefined return.
isReachable will then return a Promise that you can await for the result
If net.connect() doesn't return a Promise you will need to wrap the function implementation in a Promise and use the resolve() callback to return true/false within the .connect() and .on() callback functions.
function isReachable(hostname, port) {
return new Promise(
(resolve, reject) => {
net
.connect(port, hostname, () => {
resolve(true);
})
.on('error', () => {
resolve(false);
});
}
);
}
If net returns a promise, the correct solution, for me, should contain 'async' accros of 'await'. Take a look at the doc:
The advantage of an async function only becomes apparent when you combine it with the await keyword. await only works inside async functions within regular JavaScript code, however it can be used on its own with JavaScript modules.
await can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.
Something like this:
async function isReachable(hostname, port) {
return netResults = await net
.connect(port, hostname, () => {
console.log(true);
return true;
})
.on('error', () => {
console.log(false);
return false;
});
}

Handling async promises inside if statements

I am dealing with the following scenario in javascript. tt resembles a function from a package that return reject promise if something didn't happen. I want to Booleanize the await tt() in the test() function if that reject promise is triggered. the current setup results in catching the error and the else() block is not executed. is there a way to overcome that?
async function tt(){
return Promise.reject('failed');
}
async function test(){
if (somecondition && await tt()) //assume somecondition is true
{
console.log("accept")
}
else
{
console.log("reject")
}
}
test()
.catch(err=>console.log(err))
I want to avoid using .then(res ... ).catch(err ...)
You can tt in your own function that catches the error:
async function wrapped_tt() {
try {
await tt();
return true; // or return await tt(); depending on what tt returns
} catch {
return false;
}
}
later
if (somecondition && await wrapped_tt()) {
Of course you may want to check the error thrown by tt and only decide to return false for some of those errors.
So you don't care about the resolved value or the rejection error? Sure:
async function tt() {
return Promise.reject("failed");
}
function promiseAsBoolean(p) {
return p.then((s) => true, (e) => false);
}
async function test() {
if (somecondition && (await promiseAsBoolean(tt()))) {
console.log("accept");
} else {
console.log("reject");
}
}

How to declare success/fail return types in typescript

I have a package that simply does an HTTP call and returns either a success response or an error response. I am trying to make it so that you get IntelliSense on both success and error.
This is what I have:
class ResultSuccess {
userId: number;
id: number;
title: string;
}
class ResultError {
error: boolean;
}
export function magic(): Promise<ResultSuccess> {
return new Promise((resolve, reject) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => resolve(plainToClass(ResultSuccess, json as ResultSuccess)))
.catch(err => {
reject(plainToClass(ResultError, { error: true } as ResultError));
});
});
}
This works, and I get intelisense on the outcome but if i motify the retun to somethign like:
function magic(): Promise<ResultSuccess | ResultError>
I no longer get intelisense on the success or fail outcomes.
I'm new to typescript, can someone suggest a way to hanlde this or can someone see an issue?
Solution #1: errors are thrown
I'm new to typescript
In this case I allow myself to rewrite your magic function using async and await, because it is the way to work in 2019:
export async function magic(): Promise<ResultSuccess> {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const json = await response.json();
return plainToClass(ResultSuccess, json as ResultSuccess);
} catch (err) {
throw plainToClass(ResultError, { error: true });
}
}
The return value is a promise of ResultSuccess. The function never returns a ResultError, but it can throw it. An example on how to use it:
async function useMagic() {
try {
const result = await magic();
// 'result' is of type 'ResultSuccess'
} catch (err) {
// 'err' is of type 'any' and you know it is a 'ResultError'
}
}
Solution #2: errors are not thrown but returned
If you decide that errors must be returned as result values, you can do that:
export async function magic2(): Promise<ResultSuccess | ResultError> {
try {
// … same code as previously …
} catch (err) {
return plainToClass(ResultError, { error: true });
}
}
Then, when you use the result value, you have to determine if this is an error or a success. Here is a solution:
Write a type guard:
function isResultError(result: ResultSuccess | ResultError): result is ResultError {
return result["error"] !== undefined;
}
Then, use it:
async function useMagic2() {
const result = await magic2();
if (isResultError(result)) {
// Here, 'result' is of type 'ResultError'
} else {
// Here, 'result' is of type 'ResultSuccess'
}
}

Rewrite Promise-based code with async\await

I'm trying to rewrite this Promise-based code using async \ await:
public loadData(id: string): void {
this.loadDataAsync()
.then((data: any): void => {
// Do something with data
})
.catch((ex): void => {
// Do something with ex
});
}
public loadDataAsync(): Promise<any> {
// return Promise somehow
}
The rewritten code I have so far is:
public loadData(id: string): void {
let data: any;
try {
data = await this.loadDataAsync();
} catch(ex) {
// Do something with ex
}
// Do something with data
}
public async loadDataAsync(): Promise<any> {
// return Promise somehow
}
The problem is that I have to make loadData() method async since it has await in its body. Then, I have to return some Promise from it, since async methods must return a Promise. But I need to maintain the API of loadData() method and return void.
How can I achieve this? How do you break a never ending need for making a method as async when somewhere deep inside inner calls you're calling an async method?
Ideally if you can change the function declaration, just add the async keyword to loadData and use await inside like so:
public async loadData(id: string): void {
let data: any;
try {
data = await this.loadDataAsync();
} catch(ex) {
// Do something with ex
}
}
If you are unable to change the loadData function declaration, then you can just create an anonymous async function inside, and then call await within the anonymous function like so:
public loadData(id: string): void {
let data: any;
try {
data = (async () => { return await this.loadDataAsync() })();
} catch(ex) {
// Do something with ex
}
}
public async loadDataAsync(): Promise<any> {
return new Promise((resolve, reject) => {
// Logic goes here
resolve(data);
});
}
Whenever you use the await keyword, the surrounding function must be marked as async.
As was pointed out by the OP in the comments, in TypeScript it is best practice to mark the promise returning method with async as well (see the loadDataAsync function above), as this ensures the return type is always a promise. More info on that found here:
TypeScript Async / Await Tutorial

Categories

Resources