Search code examples
javascriptasync-awaites6-promise

Resolve promises in object tree


  1. How do I resolve foo3

  2. How can I resolve the object tree without async/await with only plain Promise (without depending on regenerator-runtime)

const p = v => {
  return new Promise(resolve => 
    setTimeout(resolve.bind(null, v), 2000)
  )
}

const tree = {
  element: p('foo'),
  children: [
    p({
      element: 'bar',
      children: null
    }),
    p({
      element: 'bar2',
      children: [
        {
          element: p('foo3'),
          children: null
        }
      ]
    })
  ]
}

const fullfill = async vtree => {
  if(vtree instanceof Promise) {
    await vtree
  } else if(Array.isArray(vtree)) {
    await Promise.all(vtree.map(fullfill))
  } else if(typeof vtree !== 'object') {
    return vtree
  } else {
    let { element, children = [] } = vtree
    if(element instanceof Promise) {
      element = await element
    }
    if(children.length) {
      children = await Promise.all(children.map(fullfill))
    }
    return {
      element,
      children
    }
  }
  return vtree
}

fullfill(tree).then(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>


Solution

  • There's hardly a reason to use async/await if all you're doing is to return the result anyway. You'd only use it for the tree node (element+children) case, but there you can easily do the transformation after the necessary Promise.all with then as well:

    function treeAll(vtree) {
      if (typeof vtree !== 'object' || vtree == null) {
        return Promise.resolve(vtree);
      } else if (vtree instanceof Promise) {
        return vtree.then(treeAll);
      } else if (Array.isArray(vtree)) {
        return Promise.all(vtree.map(treeAll));
      } else {
        return Promise.all([
          vtree.element,
          treeAll(vtree.children)
        ]).then(([element, children]) => ({
          element,
          children
        }));
      }
    }