0

Say I have some code that looks like this:

const myObject = {
   outerList : [
      {
         innerList: [
            1, 2, 3
         ]
      }, 
      {
         innerList: [
            2, 4, 6
         ]
      }
   ]
}; 

async function asyncTransform(i) {  
    return new Promise((resolve) => {
      setTimeout(() => {
          resolve(i+1); 
      }, Math.random()* 1000); 
    }); 
}

async function asyncTransformNestedObject(obj) {
   //??? 
}

asyncTransformNestedObject(myObject).then((result) => {
    console.log(result);
}); 

And I want to transform the object to this:

{
   outerList : [
      {
         innerList: [
            2, 3, 4
         ]
      }, 
      {
         innerList: [
            3, 5, 7
         ]
      }
   ]
}; 

What would the best way to do this be - ideally in a way where the async functions run simultaneously.

2
  • do we really need an async function here? Commented Feb 8, 2019 at 4:04
  • @brk Yes. This is just an example. In real life, these are API calls. Commented Feb 8, 2019 at 4:04

3 Answers 3

1
  • Array.map each inner element to a Promise returned by asyncTransform and then pass that array to Promise.all.
  • Then Promise.all each Promise.all created in step 1.

Here's an example:

const myObject = {
  outerList : [
    {
      innerList: [
        1, 2, 3
      ]
    }, 
    {
      innerList: [
        2, 4, 6
      ]
    }
  ]
}

function asyncTransform(i) {
  return new Promise(resolve => setTimeout(() => resolve(i + 1), 50))
}

function asyncTransformNestedObject(obj) {    
  const innerLists = obj.outerList.map(el => {
    return Promise.all(el.innerList.map(asyncTransform))
      .then(results => el.innerList = results)
  })
  
  return Promise.all(innerLists)
    .then((results, i) => obj.outerList.map((el, i) => ({ 
        ...el, 
        innerList: results[i] 
      })))
}


asyncTransformNestedObject(myObject).then((result) => {
  console.log(result)
})

Sign up to request clarification or add additional context in comments.

2 Comments

Note that you aren't reproducing the structure of the original object properly.
True, added a fix.
0

Here's the solution I ended up going with:

It's pretty straight forward when you think about it:

A Promise.all of a Promise.all is going to resolve at the maximum time of all the promises.

const myObject = {
   outerList : [
      {
         innerList: [
            1, 2, 3
         ]
      }, 
      {
         innerList: [
            2, 4, 6
         ]
      }
   ]
}; 

async function asyncTransform(i) {  
    return new Promise((resolve) => {
      setTimeout(() => {
          resolve(i+1); 
      }, Math.random()* 1000); 
    }); 
}

async function transformInnerObj(innerObj) {    
    const newInnerList = await Promise.all(innerObj.innerList.map(i => asyncTransform(i))); 
    return {
      innerList: newInnerList
    }; 
}

async function asyncTransformNestedObject(obj) {
   
   const newOuterList = await Promise.all(obj.outerList.map(innerObj =>       transformInnerObj(innerObj)));                                           
   return {
      outerList:  newOuterList                                  
   }; 
}

asyncTransformNestedObject(myObject).then(result => {
    console.log(result);
});

1 Comment

Minor: Functions that explicitly return a Promise, like asyncTransform don't need to be marked as async.
0

I would solve this using a recursive setTimeout/requestAnimationFrame in ES5, but if you insist on async function, this seems to do the trick:

     async function convert(arr,i = 0){
            if(!arr[i]){return arr}
            await arr[i].innerList.reduce((ac,d,i,a) => ++a[i],(async function(){}()));
            return convert(arr,++i);
        }

    convert(myObject.outerList);

//myObject
    "[
        {
            "innerList": [
                2,
                3,
                4
            ]
        },
        {
            "innerList": [
                3,
                5,
                7
            ]
        }
    ]"

You didn't specify anything about mutating the original object, so I changed it in place. I also returned the innerArray, you could have returned the object itself insteand and use await to store in a variable.

2 Comments

Not my downvote, but that's some pretty cryptic code.
@dwjohnston, I understand, np. That's why I said I'd solve with recursive ES5. I saw that you kinda emphasized async functions, so I wondered whether it'd be possible to only use async/await. The reduce part is to force the line to return a resolved Promise with undefined and await it so that all array elements are incremented, if that's the part that was cryptic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.