解决对象树中的承诺

Resolve promises in object tree

  1. 如何解决foo3

  2. 如何在没有 async/await 的情况下仅使用普通 Promise(不依赖于 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>

您的代码存在问题,您的 childrentree object 由第一个 if (vtree instanceof Promise) { 处理。他们的 child 从未处理过。

为了正确处理 child 我删除了 assigned assign awaited object 回到 vtree 里面 first if (Change 1) & 在旁边添加 vtree = await fullfill(vtree)它(更改 2)。

使用 children && children.length 所以如果 children 为 null 那么它不会抛出异常。 (改变 3)

下面进行测试。

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) {
    // Chanage 1
    // assign awaited object back to vtree
    vtree = await vtree;
    // Chanage 2
    // Call fullfill and pass vtree
    vtree = await fullfill(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
    }
    // Chanage 3
    // use children && children.length so if children is null then it won't throw exception.
    if (children && 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>


编辑 没有 await。要删除 await,我们需要 return Promise。请查看第一个代码片段,然后检查第二个代码片段中的等效版本,其中 return Promise 而不是 await.

下面进行测试。

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) {
    // Chanage 1
    // assign awaited object back to vtree
    return vtree.then(r => fullfill(r))
    //vtree = await vtree;
    //vtree = await fullfill(vtree);
  }

  // Chanage 2
  // update else if condition to if here.
  else if (Array.isArray(vtree)) {
    return Promise.all(vtree.map(fullfill))
  } else if (typeof vtree !== 'object') {
    return vtree
  } else {
    let {
      element,
      children = []
    } = vtree
    if (element instanceof Promise) {
      // element = await element
      return element.then(e => {
        if (children && children.length) {
          return Promise.all(children.map(fullfill)).then(c => ({
            element: e,
            children: c
          }));
        };
        return {
          element: e,
          children: children
        };
      });
    }
    // Chanage 3
    // use children && children.length so if children is null then it won't throw exception.
    else if (children && children.length) {
      return Promise.all(children.map(fullfill)).then(c => ({
        element: element,
        children: c
      }));
    }
  }
  return vtree
}

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

如果您所做的只是 return 结果,那么几乎没有理由使用 async/await。您只会将它用于树节点(元素+子节点)的情况,但您也可以在 之后轻松地使用 then 进行转换:

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