代码之家  ›  专栏  ›  技术社区  ›  dwjohnston

如何对嵌套结构进行映射异步转换?

  •  0
  • dwjohnston  · 技术社区  · 6 年前

    假设我有如下代码:

    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);
    }); 

    我想把这个物体转换成:

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

    最好的方法是什么-最好是异步函数同时运行的方式。

    3 回复  |  直到 6 年前
        1
  •  1
  •   nicholaswmin    6 年前
    • Array.map 承诺的每个内部元素 asyncTransform 然后将数组传递给 Promise.all .
    • 然后 Promise.all 每个 承诺所有 在步骤1中创建。

    下面是一个例子:

    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)
    })
        2
  •  0
  •   dwjohnston    6 年前

    以下是我最终采用的解决方案:

    当你想到它的时候,它是非常直截了当的:

    一个承诺。所有的承诺。所有的承诺都将在所有承诺的最长时间内解决。

    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);
    });
        3
  •  0
  •   ibrahim tanyalcin    6 年前

    我会在ES5中使用递归的setTimeout/requestAnimationFrame来解决这个问题,但是如果坚持使用异步函数,这似乎可以做到:

         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
                ]
            }
        ]"
    

    你没有指定任何关于改变原始对象的内容,所以我在适当的地方修改了它。我还返回了innerrarray,您可以返回insteand中的对象本身,并使用await存储在变量中。