Rewrite Promise-based code with async\await - javascript

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

Related

Await for a function to finish not working

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

Angular Typescript - Async await on internal subscription

I have a function like this;
openModalWhenRemoveItem() {
callRemoveService();
openMyModal();
}
callRemoveService() function has a subscribe and it's async function, the openMyModal() function must be invoked after callRemoteService()
callRemoveService() {
combineLatest(myAccountSelector$, myCompanySelector$).pipe(
switchMap(res) =>
this.myService.remove(res[0].id, res[1].id))
.subscribe((res)=> console.log(res))
}
I need to create a function that has to wait the internal subscription in callRemoveService() before calling the openModal(). I want to try with async await but I can't find a solution. I tried in this way:
async callRemoveService() {
await combineLatest(myAccountSelector$, myCompanySelector$).pipe(
switchMap(res) =>
this.myService.remove(res[0].id, res[1].id))
.subscribe((res)=> console.log(res))
}
openModalWhenRemoveItem() {
callRemoveService().then(() => {openMyModal();});
}
but it doesn't work. I cant put openMyModal() function into subscribe.
The solution in your case would be to return the Observable from the callRemoveService method instead of subscribing to it. The caveat with this approach is that you need to call subscribe in all the places where you call callRemoveService.
If you do that, then it is trivial:
callRemoveService(): Observable<any> {
return combineLatest(myAccountSelector$, myCompanySelector$).pipe(
switchMap(res) =>
this.myService.remove(res[0].id, res[1].id));
}
Then your openModalWhenRemoveItem method becomes this:
openModalWhenRemoveItem() {
callRemoveService().subscribe(() => {
openMyModal();
};
}
combineLatest is a RxJS operator, it returns an Observable. You can't simply await an Observable, it's not a Promise. Simply subscribe to it.
callRemoveService(): Observable<any> {
return combineLatest(myAccountSelector$, myCompanySelector$);
}
and then :
openModalWhenRemoveItem() {
callRemoveService().subscribe(openMyModal);
}
Alternatively, you can transform your Observable to Promise using the lastValueFrom operator, and await it :
callRemoveService(): Promise<any> {
return lastValueFrom( combineLatest(myAccountSelector$, myCompanySelector$)) ;
}
async openModalWhenRemoveItem() {
await callRemoveService();
openMyModal();
}

TypeScript / JavaScript: How to wrap a Promise object using decorator pattern

I'm attempting to wrap a TypeScript (JavaScript) Promise object with the decorator pattern because I need to add additional logic inside the Promise's then and catch methods (not shown here).
So far, it looks like this:
export class Decorator {
protected _promise: Promise<any>;
constructor(promise: Promise<any>) {
this._promise = promise;
}
then(onFulfilled: any, onRejected: any): Promise<any> {
return this._promise.then(r => onFulfilled(r), r => onRejected(r))
};
catch(onRejected: any): Promise<any> {
return this._promise.catch(r => onRejected(r));
}
}
(async () {
// Note that doSomethingAsynchronously() returns a Promise<void>
await new Decorator(doSomethingAsynchronously()); // ERROR!!
})();
However, as noted by the "ERROR!!" comment above, I get this build error:
Type of "await" operand must either be a valid promise or must not contain a callable "then" member.
I've tried experimenting with extending Promise (hence the class declaration would become export class Decorator<T> extends Promise<T>), but then I have to call super() in the constructor and pass it an executor object, which changes the Decorator class substantially. I'd like to avoid needing an executor, and would like to simply pass the inner promise into the constructor.
How can I successfully await the Decorator class's wrapped promise?
I'm really not sure what you're trying to accomplish and I agree with #jfriend00. Maybe asking what you are really trying to solve maybe you can get a better answer.
Anyway here is a way to do what you want... not sure if this is the best way... but it works...
class Decorator {
protected _promise: Promise<any>;
constructor(promise: Promise<any>) {
this._promise = promise;
}
getPromise(onFulfilled?: any, onRejected?: any): Promise<any> {
return this._promise.then(r => {
console.log('Decorator:onFulfilled');
onFulfilled(r);
})
.catch(r => {
console.log('Decorator:onRejected');
onRejected(r);
})
}
}
(async () => {
// Note that doSomethingAsynchronously() returns a Promise<void>
const doSomethingAsynchronouslyWithSuccess = () => {
return new Promise<void>((resolve, reject) => {
setTimeout(() => resolve(), 1000);
});
}
const doSomethingAsynchronouslyWithFail = () => {
return new Promise<void>((resolve, reject) => {
setTimeout(() => reject(), 1000);
});
}
await new Decorator(doSomethingAsynchronouslyWithSuccess()).getPromise();
await new Decorator(doSomethingAsynchronouslyWithFail()).getPromise();
})();

Javascript: Strange behavior when using promises, async-await, returns "Promise <pending>"

Given the following code:
async #token() {
const value = await this.belcorp.getAccessToken();
console.log(value);
}
This code returns:
But if I try to return that same result in my constructor with this code:
constructor() {
const token = this.#token();
console.log(token);
}
async #token() {
return await this.belcorp.getAccessToken();
}
returns the following:
What should I do to retrieve only the previous object?
Aside from the issue of Promises in constructors, your code returns a Promise because that is what you told it to do: async functions return Promises. If you want the awaited Promise result instead, change the line to
const token = await this.#token();
Of course, you would need your constructor to be async in this case, so you will need to move your code outside your constructor.
You cannot make a class constructor async. Instead, just make your own static constructor method -
class MyThing {
constructor(token) { // cannot be async
this.token = token // make sync instead
}
static async token() { // make static
return new Promise(r =>
setTimeout(r, 1000, "tkn123") // demo token response
)
}
static async new () { // make async constructor
return new MyThing(await this.token()) // await token
}
}
const main = async () =>
{ console.log("loading...")
const x = await MyThing.new() // <-- MyThing.new()
console.log("got token:", x.token)
return "done"
}
main().then(console.log, console.error)
// loading...
// got token: tkn123
// done

Does a async function which returns Promise<void> have an implicit return at the end of a block?

public async demo(): Promise<void> {
// Do some stuff here
// Doing more stuff
// ...
// End of block without return;
}
Is a new Promise<void> returned implicitely at the end of the block in TypeScript/ES6?
Example for boolean type:
class Test {
public async test(): Promise<boolean> {
return true;
}
public main(): void {
this.test().then((data: boolean) => {
console.log(data);
});
}
}
new Test().main();
This prints true to the console because a return inside of a async function creates a new Promise and calls resolve() on it with the returned data. What happens with a Promise<void>?
What happens with a Promise
Same thing with a function that returns void. A void function returns undefined. A Promise<void> resolves to an undefined.
function foo(){}; console.log(foo()); // undefined
async function bar(){}; bar().then(res => console.log(res)); // undefined

Categories

Resources