I have a nested object subprojects with a property of type array: userEstimates holding object(s) Estimate.
I am looking to iterate through userEstimates and push a fetch/promise to an array without calling it.
main (inside async function)
await subproject.getUserEstimates(true);
let stack = [];
subproject.userEstimates.forEach(ue =>
stack.push(ue.fetchAvailableRates)
);
console.log(stack); // 3) [ƒ, ƒ, ƒ]
await Promise.all(stack);
fillForm(subproject);
however, attributes on subproject are not defined when calling fillForm
function definition for fetchAvailableRates:
fetchAvailableRates = () => {
this.availableRates = fetch(...)
.then((resp) => {
if (resp.ok) return resp.json();
else throw new Error("Something went wrong");
})
.then((r) => {
...
return {
Rate.get(), // returns class
...
};
})
.catch((e) => {
console.error(e);
});
};
EDIT: Changed my wording frrom queue to stack as i'm trying to run all requests at once, and I don't care about order
Your definition for fetchAvailableRates uses this, but when you refer to an object's function without calling it (like stack.push(ue.fetchAvailableRates)), it loses the reference to this and simply becomes a function.
To refer to a function that calls ue.fetchAvailableRates on the ue instance at the time, you should call either () => ue.fetchAvailableRates() or ue.fetchAvailableRates.bind(ue).
That's not the only change you'd need to make―Promise.all() doesn't accept functions, only promises, so the right call is probably to make ue.fetchAvailableRates() return the Promise and add that to the stack.
Related
So what I want to achieve is that when a function returns an empty Object from the Promise, the Await function must not be executed and the rest of the Application must carry on executing other tasks. As the object that is returned maybe not always be available but should be returned when available.
function getData(Data) : Promise<Object> {
return new Promise((resolve, reject) => {
request({
// Method
}, (err, resp, file)=> {
if (err) {
reject(err);
} else {
resolve({
// Return object infomation
});
}
});
});
}
let someData = await Promise.all(data.map(getData));
// This should have a part that ignores if getData is empty and this await function ignored.
The rest of the application should be able to run as normal. I have tried to use:
.catch(error => { });
But didn't work the way I wanted it to work
There may be a better way, but what solved my issue was to pass an empty array to the data
if (isNullOrUndefined(data)) {
data = [];
}
In this way the await function now works the way I want it to work and does not throw error:
TypeError: Cannot read property 'map' of undefined
I have been on this for long now please I need assistance.
Am trying to make a call to an API link and I have an array of data to make the call as parameters to the call.
And After the call has been made I want to set the component state to the result gotten.
let animals = ['cats','goats'] ;
async.each(animals, function(item, cb){
axios.get(`http://api.com?keyword=${item}`)
.then(res=> {
apiData.push(res.data)
this.setState({
stateData: apiData
});
});
})
async.each only makes sense if you want to execute one request after another, and then you have to call cb() so that the chain continues:
async.each(array, (item, cb) => { // <- arrow func!
axios.get(`/http://api.com?keyword=${item}`)
.then(res => {
apiData.push(res.data);
this.setState({ stateData: apiData });
cb(); // <---
});
});
Or to execute all in parallel (which is probably much faster):
const promises = array.map(item => axios.get(`/http://api.com?keyword=${item}`).then(res => res.data));
Promise.all(promises).then(stateData => {
this.setState({ stateData });
});
PS: You should always handle errors in a promise, so just attach a .catch(/*..*/) to the chain ...,
Use arrow function for both forEach and api request callback, that will prevent javascript re-assigning the value of this during your callback chain.
More info about arrow functions in ES6 read: https://codeburst.io/javascript-arrow-functions-for-beginners-926947fc0cdc
I am in my cart actions and I am calling loadCartItems() from another function within the same file. However, this function is not returning a promise or any data and I do not know why. My loadCartItems() function is not even being recongized as a function actually. Does anyone know why this might be?
export function loadCartItems() {
return (dispatch, getState) => {
dispatch({
type: types.LOAD_CART_PRODUCTS
});
return AsyncStorage.getItem(STORAGE_KEY_JWT_TOKEN).then((key) => {
return API.getCartItems(key)
.then((response) => {
return dispatch({
type: types.LOAD_CART_PRODUCTS_SUCCESS,
response
});
}).catch(err => {
console.log('Error retrieving cart products');
})
}).catch(err => {
console.log("Error retrieving cart items from local storage");
});
};
}
export function getUnaddedCartItems() {
return (dispatch, getState) => {
dispatch({
type: types.GET_UNADDED_ITEMS
});
return AsyncStorage.getItem(STORAGE_KEY_CART_ITEMS).then((result) => {
const addedItems = JSON.parse(result);
loadCartItems()
.then((result) => {
const cartItems = result.response.products;
if (this.state.unaddedCartItems.length === 0) {
const unaddedCartItems = addedItems.filter((addedItem) => {
return cartItems.find(cartItem => cartItem.id !== addedItem.productId);
});
}
}).catch(err => {
consoel.log('error: ', err);
});
}).catch(error => {
console.log('error: ', error);
});
};
}
this.loadCartItems() isn't a function. loadCartItems() is.
Since they aren't in a common class/object/something, there is no need to use this. It basically acts like a global (within the context of that file), so just call it directly.
Looking at it a bit closer, it looks like you are trying to call an action creator within an action creator. That's your problem.
Normally, you map these actions within your component, so it takes care of the dispatch bit for you. However, when you are calling the function directly yourself, you need to also deal with it yourself.
loadCartItems().then is the thing that isn't a function now that you've removed the this. That makes sense, since loadCartItems() actually returns a function, not a Promise. The function accepts two arguments: dispatch and getState.
You need to call it like this: loadCartItems()(dispatch, getState).then().
It doesn't actually say loadCartItems() is not a function
It says loadCartItems(...).then is not a function.
What does it mean?
In fact, loadCartItems(...).then is not a function, because the function doesn't return a Promise. It returns another function!
As stated in redux-thunk docs:
Any return value from the inner function will be available as the return value of dispatch itself.
So, in order to properly call your loadCartItems() action, you should do
dispatch(loadCartItems(anyParamYouWant)).then(...)
I'd recommend you to take a look at redux-thunk docs to help you get a better understanding on how thunks works ;)
Both loadItems and getUnaddedCartItems return thunks, not promises.
They therefore need to be dispatched first, so that they return the promises you're expecting.
That dispatch code before you return the promise seems to be unnecessary so if you in fact don't need it, just have the functions return the promises.
Let's say I have two async events, both need to i/o with remote exchange.
placeOrder()
cancelOrder()
Both events fire in async way, which means cancelOrder can be called before placeOrder return. Tricky part is I need the placeOrder to return an Order ID first otherwise there is no way to call cancelOrder, so I need some way to block the cancelOrder event right until placeOrder returns, and the blockage cannot be too long otherwise the Order may be executed, so loop/timeout/frequent checking doesn't work here.
Any idea?
You would use a Promise for that. If your functions already return a promise, you can simply chain the both functions using then()
placeOrder().then(val => cancelOrder(val));
If they do not, you can put them inside a new Promise
function foo() {
return new Promise((resolve, reject) => {
// do stuff
resolve('<result of placeOrder here>');
});
}
function bar(val) {
return new Promise((resolve, reject) => {
// do stuff
resolve('whatever')
})
}
and call
foo()
.then(value => bar(value))
.then(console.log);
If you are able to use ES2017, the you can use async functions. For example, I'm going to assume that your functions perform some sort of request to the database using fetch or axios since you haven't specified. Then you can write placeOrder and cancelOrder like so:
const placeOrder = async () => {
try {
const response = await fetch('/place_order');
// Do something with the response
} catch (err) {
// Handle error
}
};
const cancelOrder = async () => {
try {
const response = await fetch('/cancel_order');
// Do something with the response
} catch (err) {
// Handle error
}
};
const someFunction = async () => {
await placeOrder();
await cancelOrder();
};
Kind of a sequel to this question, I need to accept multiple objects in a POST request and then for each object process it, save it, and then return the saved object to the frontend (so that the client can see which columns were successfully edited).
When I use .map, it does save to the database and I can confirm this. However, I have two problems:
It does not execute res.locals.retval.addData(dtoObject); correctly, and my returning payload has no data transfer objects inside of it.
My object validation cannot be done inside of the callback of map. I initially tried reduce, but that didn't work at all and just saved all the same values to each database object. How can I exclude invalid JSON objects while I'm mapping them?
var jsonObjects = req.body;
//for (var n in req.body) {
var promises = jsonObjects.map((jsonObject) => {
var transform = new Transform();
// VALIDATION OF jsonObject VARIABLE IS HERE
if (jsonObject.id == 0) {
var databaseObject = Database.getInstance().getModel(objectName).build(jsonObject);
transform.setNew(true);
transform.setJsonObject(jsonObject);
transform.setDatabaseObject(databaseObject);
transform.baseExtract()
.then(() => transform.extract())
.then(() => transform.clean())
.then(() => transform.getDatabaseObject().save())
.then(function(data) {
// PROCESSING DATA
}).catch((e) => {
// ERROR
});
} else {
var queryParameters = {
where: {id: jsonObject.id}
};
console.log("Query parameters: ");
console.log(queryParameters);
Database.getInstance().getModel(objectName).findOne(queryParameters).then((databaseObject) => {
transform.setJsonObject(jsonObject);
transform.setDatabaseObject(databaseObject);
})
.then(() => transform.baseExtract())
.then(() => transform.extract())
.then(() => transform.clean())
.then(() => transform.getDatabaseObject().save())
.then((data) => {
// PROCESSING DATA
}).catch((e) => {
// ERROR
});
}
});
Promise.all(promises)
.then((results) => {
return next();
}).catch((e) => {
throw e;
});
Here's the resulting payload:
{
"errors": [],
"warnings": [],
"data": []
}
As #KevinB said in the comments, you are missing the return calls inside of your arrow functions so the database saves are going through because they are part of the Promise chain, but pushes to the response are stalled waiting for the return, and then the Express.js call resolves before the Promises do. Add return Database.getInstance() and return transform.baseExtract() to your code to fix this.
Use Array.prototype.filter() to remove elements you want to ignore since you won't ever need to execute Promises on them, then call Array.prototype.map() on the resulting array. If you don't want to use the arrow functions, you can specify this as a parameter to filter and map:
jsonObjects.filter(function(jsonObject) {
}, this);
var promises = jsonObjects.map(function(jsonObject) {
}, this);