0

Ok so i've searched around and found nothing related to this problem.

My problem is something like this ->

I create an object (push into array) with some info taken from an api. After getting the info from the api i need to call yet another API to get further information on users. Since there are multiple keys for users i'd like to be able to set them inline with a simple function.

I'm doing something like this ->

_item.push({
    Author: setPeople(item.Author.Title),
    Title: item.Title,
    ....
    Requester: setPeople(item.Requester.Title
})

At the moment i am getting the promise set(entirely) and not the PromiseValue. I know you usually do something like setPeople(name).then(() => {}) however that is not working in my object (sets the key too fast).

Any tip on how i should approach this?

Updating with more code.

export const retrieveIrfItems = async (spId) => {
    let spQuery = "SITE" + SpQueryExtend1 + spQueryExpand;

    return new Promise((resolve, reject) => {
        let _items = [];
        axiosApi.get(SiteUrl + spQuery).then((response) => {
            //console.log(response.data.d);
            return response.data.d;
        }).then(async (item) => {
            //let requesterSP = setPeople()
            const createSPUser = async (user) => {
                let spUser;
                console.log("User prop is");
                console.log(user);
                setPeople(user).then((item) => {
                    spUser = item;
                });
                return spUser;
            }

                _item.push({
        Author: setPeople(item.Author.Title),
        Title: item.Title,
        ....
        Requester: setPeople(item.Requester.Title
    })

Ignore the unused function, i'm still doing tests to find a way for this problem.

Found the fix thanks to comments.

Using async/await wouldnt help me since i'd still get promise pending or undefined. What i had to use is ->

Requester: await setPeople(item.Requester.Title).then((user) => { return user }), Using that in my object seems to work, but my question is...how good is this approach? If there are lots of fields with this behaviour (currently 5), wouldnt that slow down the page by...a lot ?

Dante R.
  • 902
  • 3
  • 13
  • 41
  • 2
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Liam Dec 20 '18 at 14:55
  • 1
    Did you try using the async-await flow? – asiby Dec 20 '18 at 14:56
  • I doubt its a duplicate since the context is different. Can't use async since my object is created in the `.then()` of the first API call. Doesnt seem like a good practice (also its setting it as undefined if i do that). – Dante R. Dec 20 '18 at 15:00
  • @asiby that actually worked (with a bit of a workaround. Thanks for the idea. Now i wonder how it will behave when there are lots of items/fields.. – Dante R. Dec 20 '18 at 15:08
  • No that wouldn't be practical .. You can `await Promise.all()`. Also note that wrapping `axiosApi.get()` in `new Promise()` is an anti-pattern when you can `return axiosApi.get()` – charlietfl Dec 20 '18 at 15:12
  • How would i be able to use await Promise.All() in my object tho'? Since there are different promises (I'm calling setPeople for each field). – Dante R. Dec 20 '18 at 15:22
  • is your `createSPUser` usefull ? what if the purpose of `retrieveIrfItems` ? should it return your `_item` array ? – dun32 Dec 20 '18 at 15:43
  • `createSPUser` is there just for testing purposes (not used at the moment). `retrieveIrfItems` returns the `_items` array on component load in react as such -> `retrieveIrfItems(this.props.selected.Id).then((item) => { this.props.setDefaultFields(item[0]); });` – Dante R. Dec 20 '18 at 15:45

1 Answers1

1

Then you should try something like that :

export const retrieveIrfItems = async (spId) => {
  return new Promise((resolve, reject) => {
    let spQuery = "SITE" + SpQueryExtend1 + spQueryExpand;
    let _items = [];
    try{
      const axiosApiItem = await axiosApi.get(SiteUrl + spQuery);
      const item = axiosApiItem.data.d;
      _item.push({
        Author: await setPeople(item.Author.Title),
        Title: item.Title,
        ...
        Requester: await setPeople(item.Requester.Title)
      });
      return resolve(_items);
    }catch(e){
      return reject(e);
    }
  });
}

Async / await is a way to consume async Promise functions. The async keyword tells the javascript compiler that this function will consume one or more asynchronous functions. The await keyword tells the compiler that the next function call is asynchronous and returns a promise.

In your code, your first then() function should return a promise which is not the case, that's why the second then() can't be reached.

Also, in your code, your new Promise doesn't return anything. When you create a new Promise, you have to end it by calling resolve() or reject.

Hope it helps...

dun32
  • 708
  • 6
  • 9
  • Thats pretty much how i modified my code. I already had `resolve()` but it was in another `then()` (there's one more and my first `then()` was doing `return _items`. Thing is, it works and all, but isnt this a bit heavy on performance ? (Fact is there are about 3 api calls for a single item object and no way to work around this unfortunately). EDIT: Takes about 4 seconds to populate my form with API data with 3 people fields (i'll have around 7-9) so it sounds like 1 second per field. – Dante R. Dec 20 '18 at 16:01
  • 1
    there's a lot of different ways to achieve that king of calls, with `async` library, `rxjs` library, ... which have each goods and bads. In your case, you only use standard javascript functions so I don't think it's the worse way to do that. The only way for you to increase performances would be to add a function on the server API to perform all the requests locally then send you the final result. – dun32 Dec 20 '18 at 16:09
  • Ok so no library can help with the speed. I'll just try to minify my app as much as i can then. Thanks! – Dante R. Dec 20 '18 at 16:11