working with Node js Await/Async functions - javascript

This is my axios Request to call the API.
export function axiosGet (url) {
return opsutils.get(url)
.then(function (response) {
return response.data.data;
})
.catch(function (error) {
return 'An error occured..' + error;
})
}
From here i'm calling it asynchrously
async getDirList(data){
this.domainDir=data.domain_name
var apiurl="some URL"
var stat = await axiosGet(apiurl)
if (status){
this.domainlog= stat
}
From here i'm calling the async func defined above
Notify(data){
var filelist = this.getDirList(data)
if(filelist){
var status = createNotification(data.domain_name,message_stripped,'Degrading web server performance')
}
The ideal should be like this that it should go forward only after the promise is resolved ,right now the var filelist got empty.
How do i get to solve this problem ?Thanks in advance

The problem is this.getDirList(data) is not being accessed asynchronously as well. Remember, because that is async now, it's returning a promise, so you either need to chain it with .then():
Notify(data){
var filelist = this.getDirList(data)
.then(data => {
var status = createNotification(data.domain_name,message_stripped,'Degrading web server performance')
});
}
Or turn Notify() into an async function as well:
async Notify(data){
var filelist = await this.getDirList(data);
if(filelist){
var status = createNotification(data.domain_name,message_stripped,'Degrading web server performance')
}
Additionally, make sure you're actually returning data from getDirList so you can utilize the return value when you await it.

Related

How can multiple unconnected async events await a single promise

I have a system where I need an id from a server to handle events. I should only fetch the id if/when the first event happens, but after that, I need to use the same id for each subsequent event. I know how to use async-await etc. so I have some code like this
var id = "";
async function handleEvent(e) {
if (! id ) {
let response = await fetch(URL)
if (response.ok) {
let json = await response.json();
id = json.id ;
}
}
// use id to handle event
}
But my problem is that I could receive multiple events before I receive a response, so I get multiple overlapping calls to fetch a new id.
How can I have multiple asynchronous calls to handleEvent, with the first one processing the fetch and any subsequent call waiting for it to complete to access the result?
Create a function to ensure you only make one request for the id using a lazy promise.
const URL = 'whatever'
let idPromise // so lazy 🦥
const getId = async () => {
const response = await fetch(URL)
if (!response.ok) {
throw response
}
return (await response.json()).id
}
const initialise = () {
if (!idPromise) {
idPromise = getId()
}
return idPromise
}
// and assuming you're using a module system
export default initialise
Now all you have to do is prefix any other call with initialise() to get the ID which will only happen once
import initialise from 'path/to/initialise'
async function handleEvent(e) {
const id = await initialise()
// do stuff with the ID
}
The currently accepted response relies on a global variable, which is not ideal. Another option is to use a class.
class IDManager {
getId(URL) {
if (this.id) {
return this.id;
}
this.id = fetch(URL)
return this.id
}
}
Then when you call getId, you simply await the result. If no previous request has been made, a network request will be sent. If there is already a pending request, every call will await the same result. If the promise is already resolved, you will get the result immediately.
const idManager = new IDManager();
async function handleEvent() {
const id = await idManager.getId(URL);
// Do stuff with the ID.
}
Not clear why your function is parameterized by "e".
I would write it in a more straightforward manner:
async function request(URL) {
let response = fetch(URL)
if (response.ok) {
let json = await response.json();
return json.id;
}
return false;
}
Then if the sequence of your calls matters write them one by one.
If not then you could use Promise.all (Promise.allSettled maybe) to run them all at once.
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
The solution to this turned out to be a little different from the previous answers. I thought I would post how I made it work in the end. The answers from #phil and #vaelin really helped me to figure this out.
Here was my solution...
class IDManager {
async fetchID (resolve,reject ) {
const response = await fetch( URL, { } ) ;
const id = await response.json() ;
resolve( id );
}
async getID() {
if ( this.id === undefined ) {
if ( this.promise === undefined ) {
var self = this;
this.promise = new Promise( this.fetchID ).then( function(id) { self.id = id;} );
}
await this.promise;
}
return this.id;
}
}
The problem was that awaiting the fetch the getID call took a couple of seconds. During that time there were often multiple calls to getID, all of which initiated another fetch. I avoided that by wrapping the fetch and response.json calls in another promise which was created instantly, and so avoided the duplicates.

Wait for Algolia response before returning Cloud Function

I have just implemented algolia in my back-end and I tested it with an http function.
However I now need to use Algolia's search with a callable function. The problem is, it's returning the (null) results before Algolia gives a response (due to being async).
I know I should probably make a promise and wait for algolia to return, but how can I do this? Algolia uses it's own methods and I'm not sure how to implement a promise.
On their documentation there's an example on how to wait for the response, but it only shows it for adding or getting a single object, which is treated differently than a search.
Here's my function:
exports.searchDataInAlgolia = functions.https.onCall((data, context) => {
var algoliaClient = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_ADMIN_KEY);
var ALGOLIA_INDEX_NAME = 'users';
var algoliaIndex = algoliaClient.initIndex(ALGOLIA_INDEX_NAME);
algoliaIndex.search({
query: data.textToSearch
})
.then(function (responses) {
return responses.hit;
});
})
How can I wait for algolia to fetch all the data before returning responses.hit?
This is how I'm calling the cloud function:
searchForUser = (textToSearch) => {
var searchDataInAlgolia = firebase.functions().httpsCallable('searchDataInAlgolia');
searchDataInAlgolia({
textToSearch: textToSearch,
}).then(function (result) {
return result.data;
//Future data manipulation/filtering
}).then(res => {
console.log(res);
})
}
And I call this function from an onPress on RN passing a string parameter, but that's not the issue for sure.
You need to return the result of search too:
exports.searchDataInAlgolia = functions.https.onCall((data, context) => {
var algoliaClient = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_ADMIN_KEY);
var ALGOLIA_INDEX_NAME = 'users';
var algoliaIndex = algoliaClient.initIndex(ALGOLIA_INDEX_NAME);
return algoliaIndex.search({
query: data.textToSearch
})
.then(function (responses) {
return responses.hit;
});
})
Without that the function ends as soon as the last }) is executed, instead of waiting for the results from Algolia to come back (asynchronously).

How to get data returned from fetch() promise?

I am having trouble wrapping my head around returning json data from a fetch() call in one function, and storing that result in a variable inside of another function. Here is where I am making the fetch() call to my API:
function checkUserHosting(hostEmail, callback) {
fetch('http://localhost:3001/activities/' + hostEmail)
.then((response) => {
response.json().then((data) => {
console.log(data);
return data;
}).catch((err) => {
console.log(err);
})
});
}
And this is how I am trying to get the returned result:
function getActivity() {
jsonData = activitiesActions.checkUserHosting(theEmail)
}
However, jsonData is always undefined here (which I am assuming is because the async fetch call has not finished yet when attempting to assign the returned value to jsonData. How do I wait long enough for the data to be returned from the fetch call so that I can properly store it inside of jsonData?
always return the promises too if you want it to work:
- checkUserHosting should return a promise
- in your case it return a promise which return the result data.
function checkUserHosting(hostEmail, callback) {
return fetch('http://localhost:3001/activities/' + hostEmail)
.then((response) => {
return response.json().then((data) => {
console.log(data);
return data;
}).catch((err) => {
console.log(err);
})
});
}
and capture it inside .then() in your main code:
function getActivity() {
let jsonData;
activitiesActions.checkUserHosting(theEmail).then((data) => {
jsonData = data;
}
}
EDIT:
Or even better, use the new syntax as #Senthil Balaji suggested:
const checkUserHosting = async (hostEmail, callback) => {
let hostEmailData = await fetch(`http://localhost:3001/activities/${hostEmail}`)
//use string literals
let hostEmailJson = await hostEmailData.json();
return hostEmailJson;
}
const getActivity = async () => {
let jsonData = await activitiesActions.checkUserHosting(theEmail);
//now you can directly use jsonData
}
You're partially right. It's because you're trying to get the result of this asynchronous call in a synchronous fashion. The only way to do this is the same way you deal with any other promise. Via a .then callback. So for your snippet:
function getActivity() {
return activitiesActions.checkUserHosting(theEmail).then((jsonData) => {
// Do things with jsonData
})
}
Any function that depends on an asynchronous operation must itself become asynchronous. So there's no escaping the use of .then for anything that requires the use of the checkUserHosting function.
You can make use of new ES6 and Es7 syntax and what others have written is also correct, but this can be more readable and clean,
you are trying to get aysnc value synchronously, here jsonData will be undefined because, you move to next line of execution before async function(checkUserHosting) is finish executing, this can be written as follows
const getActivity = async () => {
let jsonData = await activitiesActions.checkUserHosting(theEmail);
//now you can directly use jsonData
}
and you can write checkUserHosting in a different using new syntax like this
const checkUserHosting = async (hostEmail, callback) => {
let hostEmailData = await fetch(`http://localhost:3001/activities/${hostEmail}`)
//use string literals
let hostEmailJson = await hostEmailData.json();
return hostEmailJson;
}

Fetching return value from async function

I am trying to capture the response of two service calls within a function. Got to know that async and await will solve this purpose and tried below. Here inside async function ex - I am making a call to users, companies end point and console log is displaying perfect, but while retrieving the same value by calling the async function is giving Promise Pending. I tried two options 1. by simply calling the async function - giving Promise Pending 2. by calling with await prefixed - giving await is a reserved word.
Please let me know how to capture the response from this...
const service = {
getUsers: () => axios.get(`http://localhost:3000/users`),
getCompanies: () => axios.get('http://localhost:3000/companies')
};
let ex = async () => {
let users = {};
let companies = {};
try {
users = await service.getUsers()
companies = await service.getCompanies()
console.log('Example ', {
users: users.data,
companies: companies.data
})
} catch (err) {
console.log(err);
}
return [{ users, companies}];
};
//let resp = await ex(); - giving await is a reserved word
// let resp = ex(); - giving Promise is pending..
console.log(resp);
All async functions will always return a promise. If you return nothing, the function will return a promise for undefined. Whatever you return will get wrapped up in a promise, which you need to await or call then on to access the value inside.
resp.then(console.log)

block js execution until async request is completed

I have a problem with prefetching resources for react app. I have a function which should fetch json resources and assign them to a object properties in a loop. The function should then return the object with jsons allready resolved, but instead of it returns the object with properties as unresolved promises.
Is it possible to stop executing js code until the promises are fullfiled so the function will return correct data ?
Yes, something like a synchronous request.
async function getJson (file, url) {
const response = await fetch(`${url}/${file}.json`);
const json = await response.json();
return json;
}
async function getTranslations(files, url) {
let r = {};
files.map( (file, i) => {
r[file] = await getJson(file, url);
});
return r;
}
I don't think you should be using 'map' like that - to populate an object you're better with forEach. Though I couldn't guarantee that's the issue.
async function getTranslations(files, url) {
let r = {};
files.forEach(file => r[file] = await getJson(file, url));
return r;
}

Categories