calling an async function in the constructor. - javascript

getUser is an async function? if it is going to take longer time to resolve? is it going to always return the right value in my someotherclass.
class IdpServer {
constructor() {
this._settings = {
// some identity server settings.
};
this.userManager = new UserManager(this._settings);
this.getUser();
}
async getUser() {
this.user = await this.userManager.getUser();
}
isLoggedIn() {
return this.user != null && !this.user.expired;
}
}
let idpServer = new IdpServer();
export default idpServer;
// another class
// import IdpServer from '...'
class SomeOtherClass {
constructor() {
console.log(IdpServer.isLoggedIn());
}
}

This is a problem that is related to this popular question.
Once a code is asynchronous, it cannot be used in synchronous manner. If the use of raw promises is unwanted, all control flow should be performed with async functions.
The problem here is that getUser provides a promise of user data, not user data itself. A promise is lost in constructor, and this is antipattern.
One way to solve the problem is to provide initialization promise for IdpServer, while the rest of API will be synchronous:
class IdpServer {
constructor() {
...
this.initializationPromise = this.getUser();
}
async getUser() {
this.user = await this.userManager.getUser();
}
isLoggedIn() {
return this.user != null && !this.user.expired;
}
}
// inside async function
await idpServer.initializationPromise;
idpServer.isLoggedIn();
Depending on how the application works, IdpServer.initializationPromise can be handled on application initialization to guarantee that all units that depend on IdpServer won't be initialized until it's ready.
Another way is to make IdpServer entirely asynchronous:
class IdpServer {
constructor() {
...
this.user = this.getUser(); // a promise of user data
}
async getUser() {
return this.userManager.getUser();
}
async isLoggedIn() {
const user = await this.user;
return user != null && !user.expired;
}
}
// inside async function
await idpServer.isLoggedIn();
It's expected that all units that depend on it will also have asynchronous API.

Related

Angular make an api call async and use the result

I'm trying to make an API call
ngOnInit(){
this.function1()
}
function1(){
this.userService.getUser()
.then((data) => {
this.user = data.user
this.userM = data.userM
// here problem: If I make a console.log(this.userM) it result at the beginning empty
if(this.userM.length > 0 ) {
console.log("goInside")}
else {
console.log("doesn't enter")
//it enters always there
}
}
}
in my service:
async getUser(): Promise<any>{
let user: any = []
let userM: any = []
//.... operation to populate
return {user, userM}
}
When I make an api call I would to use the this.userM array to make some operations. But it results always empty at the beginning, but it doens't enter anymore in if. How can I do?
Make use of rxjs, try using an Observable instead:
import { of } from 'rxjs';
getUsers(): Observable<any> {
let user: any = []
let userM: any = []
//.... operation to populate
return of({user, userM});
}
And then, within your component:
ngOnInit(){
this.function1()
}
function1(){
this.userService.getUser().subscribe((response) => {
const { user, userM } = response;
if (userM.length) console.log('There is data in it!')
else console.log('No data found...');
});
}
I suggest not using Promises in an Angular project unless necessary, you have at your disposal rxjs along with tons of useful operators for handling async calls/streams of data

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

React Native Do not use setState in componentDidMount (react/no-did-mount-set-state)

playing with react native and API I've faced this kind of issue:
Do not use setState in componentDidMount (react/no-did-mount-set-state)
Who knows the reason behind?
Here my piece of code
Home.js
state = {
users: []
}
async componentDidMount() {
const users = await ajax.fetchUsers();
this.setState({users});
}
Here FetchData.js
async fetchUsers() {
try {
let response = await fetch(URI + '/users');
let responseJsonData = await response.json();
return responseJsonData;
}
catch(e) {
console.log(e)
}
}
My guess is that you're getting that error because the tool in question doesn't realize you've added async to componentDidMount, so it thinks you're synchronously setting state in componentDidMount.
You shouldn't do that. componentDidMount is not defined as an async method in React.Component. Don't make methods async when they aren't defined that way by the class you're extending. Nothing handles the promise that you'd be returning if you made componentDidMount async.
Instead, use a wrapper async function (and handle errors!!):
componentDidMount() {
(async() => {
try {
const users = await ajax.fetchUsers();
this.setState({users});
} catch (e) {
// ...handle/report error here...
}
})();
}
Or even break it out as its own method:
componentDidMount() {
this.loadInitialUsers(); // Note: No `await`
}
async loadInitialUsers() {
// Important: This must not throw any errors, because nothing handles
// the promise rejection that would create
try {
const users = await ajax.fetchUsers();
this.setState({users});
} catch (e) {
// ...handle/report error here...
}
}

Async ES2017 Constructor

What is the most up to date method to ensure that some asynchronous code completes in a class constructor before that class is subsequently used?
Specifically, how would an API client class retrieve an access token before allowing more method calls, as shown below?
class API_Client {
constructor(...) {
# Below should 'block' other method calls until token is assigned
this.login().then(res => {
this.token = res.data.token;
});
}
async login() {
return makeRequest(...) # <-- Promise which returns access token data
}
}
const client = new API_Client(...);
client.someAuthOnlyMethod() # <-- Should only happen after the `login` method completes.
I found older answers, yet couldn't quite understand how to solve the problem posed in the first comment left on the linked answer.
The most up-to-date method is still not to put any asynchronous stuff in the constructor. In your specific case, that's
class API_Client {
constructor(token) {
this.token = token;
}
static async createLoggedIn(…) {
const res = await makeRequest(...) # <-- Promise which returns access token data
return new this(res.data.token);
}
}
const client = await API_Client.createLoggedIn(…);
client.someAuthOnlyMethod()
You could store the token as a promise:
class API_Client {
constructor(...) {
# Below should 'block' other method calls until token is assigned
this.token = this.login()
.then(res => res.data.token)
}
async someAuthOnlyMethod() {
let token = await this.token;
//...continue
}
async login() {
return makeRequest(...) # <-- Promise which returns access token data
}
}
const client = new API_Client(...);
client.someAuthOnlyMethod() # <-- Should only happen after the `login` method completes.
You shouldn't be calling any asynchronous code from a constructor to begin with. In the case above, your makeRequest function would worry about the login token.
There is also no real value in a class in this case. You should just export a series of functions to make the API calls.

How to throttle typescript functions that return output

I am writing a node.js application using typescript. My application will have several services communicating with each other. Several of the services need to call an external API. This API has a restriction on the number of calls per second that can be executed. Because of this I want to create one service that wraps the external API calls (let's call it ApiService). The other services will call this one and it will collect their requests in a queue and execute them sequentially - N requests per second (for simplicity let's assume 1 per second). When service A calls a method of the ApiService - it expects to receive an output (it is fine to receive a Promise).
Now my question is - how to queue these API calls in the ApiService, so that every 1 second the next call in the queue is executed and also return the output of that API call to the caller of the ApiService?
Here's a sample service:
export class ServiceA {
apiService: ApiService;
public constructor(_apiService: ApiService) {
apiService = _apiService;
}
public async DoWork() {
// Do some stuff
const output: number = await apiService.RetrieveA(param1, param2);
// Do something with the output
}
}
The ApiService:
export class ApiService {
queue: (() => Promise<any>)[] = [];
public async RetrieveA(param1, param2): Promise<number> {
const func = async () => {
return this.CallApi(param1, param2);
};
this.queue.push(func);
return func();
}
public async RunQueue() {
while(true) {
const func = this.queue.shift();
if (!func) { continue; }
// Call the function after 1 second
await setTimeout(() => { func(); }, 1000);
}
}
private async CallApi(param1, param2): Promise<number> {
// Call the external API, process its output and return
}
}
The main method that orchestrates the whole thing:
var CronJob = require('cron').CronJob;
const apiService = new ApiService();
const service = new ServiceA(apiService);
new CronJob('* * * * * *', function() {
service.DoWork();
}, null, true);
apiService.RunQueue();
The problem I am facing is that when RetrieveA method returns func() - the function gets executed. I need to return a Promise but the actual function execution needs to happen in RunQueue() method. Is there a way to achieve this? Can I return a promise without executing the function right away and upon awaiting this promise - to receive the output when the function is called in the RunQueue method?
Or is there a different approach to solving my issue of throttling API calls that return output?
I am new to the Node.js/Typescript/JavaScript world, so any help is appreciated :)
All of that could be a lot simpler if you want to restrict calls to RetreiveA to 2 per second:
//lib is here: https://github.com/amsterdamharu/lib/blob/master/src/index.js
import * as lib from '../../src/index'
const twoPerSecond = lib.throttlePeriod(2,1000);
export class ApiService {
public RetrieveA(param1, param2): Promise<number> {
//removed the resolver part, according to the typescript signature
// it should return a promise of number but resolver actually takes
// that number and returns void (undefined?)
return twoPerSecond(this.CallApi.bind(this))([param1, param2]);
}
//change the signature of this function to take one parameter
// but deconsruct the array to param1 and param2
private async CallApi([param1, param2]): Promise<number> {
// Call the external API, process its output and return
}
}
Your method only works if there is only ever one instance of this class. If you were to create multiple instances and call RetrieveA on those instances you no longer limit requests to callApi.
I did manage to find a working solution. I'm not very familiar with the whole Promise and async concept in JavaScript, so this may not be the best solution, but it does the job for my specific case. Here is the code for anyone else looking to implement something similar:
The sample ServiceA remains the same as above:
export class ServiceA {
apiService: ApiService;
public constructor(_apiService: ApiService) {
apiService = _apiService;
}
public async DoWork() {
// Do some stuff
const output: number = await apiService.RetrieveA(param1, param2);
// Do something with the output
}
}
Here's the modified ApiService that returns promises for the output and throttles the actual function execution:
export class ApiService {
// We keep the functions that need to be executed in this queue
// and process them sequentially
queue: (() => void)[] = [];
public async RetrieveA(param1, param2): Promise<number> {
// This resolver serves two purposes - it will be called when the
// function is executed (to set the output), but will also be part
// of the Promise that will be returned to the caller (so that the
// caller can await for the result).
let resolver: (value: number) => void;
// This function will be executed by the RunQueue method when its
// turn has come. It makes a call to the external API and when that
// call succeeds - the resolver is called to return the result through
// the Promise.
const func = async () => {
return this.CallApi(param1, param2).then(resolver);
};
this.queue.push(func);
// This is the promise that we return to the caller, so that he
// can await for the result.
const promise = new Promise<number>((resolve, reject) => {
resolver = resolve;
});
return promise;
}
public async Run() {
this.RunQueue(this.queue);
}
private async RunQueue(funcQueue: (() => void)[]) {
// Get the first element of the queue
const func = funcQueue.shift();
// If the queue is empty - this method will continue to run
// until a new element is added to the queue
if (func) {
await func();
}
// Recursively call the function again after 1 second
// This will process the next element in the queue
setTimeout(() => {
this.RunQueue(funcQueue);
}, 1000);
}
private async CallApi(param1, param2): Promise<number> {
// Call the external API, process its output and return
}
}
I hope the comments in the code make it clear what (and how) I'm trying to achieve.

Categories

Resources