【问题标题】:How to resolve Promises in recursive JSON如何在递归 JSON 中解析 Promise
【发布时间】:2019-08-18 05:26:44
【问题描述】:

我需要递归遍历 JSON 并在某些情况下调用远程 API。我需要返回最后修改的整个 JSON,但我不知道如何等到 所有承诺都实现

const getObjectsOfRelated = (xmlAsJson, token) => {
  if (testIfIwantCallApi()) {   
    const jsonToReturn = JSON.parse(JSON.stringify(xmlAsJson))
    jsonToReturn.elements = callApi(xmlAsJson.text).then(result => {
      return result.data
    })
    return jsonToReturn
  }
  if (xmlAsJson.elements) {
    const jsonToReturn = JSON.parse(JSON.stringify(xmlAsJson))
    jsonToReturn.elements = xmlAsJson.elements.map(res => getObjectsOfRelated(res, token))
    return jsonToReturn
  }
  return xmlAsJson
}

即使我尝试使用 setTimeout 破解它,结果也不包括使用外部 API 创建的部分。

这样代码返回正确的结构,带有承诺而不是值我希望它要么返回已完成的承诺,要么能够等到承诺完成

【问题讨论】:

  • jsonToReturn.elements = xmlAsJson.elements.map(res => getObjectsOfRelated(res, token)) ... 在此代码中,jsonToReturn.elements 将是一个承诺数组...无论您返回jsonToReturn,您都将返回一个未履行承诺的对象( s)
  • 如果您阅读它,请不要介意已删除的评论...阅读您的代码错误 - 结果xmlAsJson 绝不是 JSON,它只是一个对象 - 而jsonToReturn 也不是 JSON - 我'd 建议使用不会混淆的变量名 ...
  • 您能否提供输入xmlAsJson 的示例以及您希望返回的内容?顺便说一句,即使你做的一切都正确,你永远不会改变xmlAsJson,因此该函数将返回输入xmlAsJson不变
  • JSON.parse(JSON.stringify(xmlAsJson))。为什么要字符串化然后解析?

标签: javascript json recursion promise


【解决方案1】:

使用 Promise.resolve 在 Promise 中包装简单的返回值:

const getObjectsOfRelated = (xmlAsJson, token) => {
  if (testIfIwantCallApi()) {   
    const jsonToReturn = JSON.parse(JSON.stringify(xmlAsJson))
    return callApi(xmlAsJson.text).then(result => {
      jsonToReturn.elements = result.data;
      return jsonToReturn;
    })
  }
  if (xmlAsJson.elements) {
    const jsonToReturn = JSON.parse(JSON.stringify(xmlAsJson))
    Promise.all(xmlAsJson.elements.map(res => getObjectsOfRelated(res, 
    token)).then((results) => {
      jsonToReturn.elements = results.map(result => result.data);
      return jsonToReturn;
    });
  }
  return Promise.resolve(xmlAsJson);
}

这样,您将始终如一地返回承诺,并且您可以像这样使用您的函数: getObjectsOfRelated(xmlAsJson, token).then(result => console.log(result))

【讨论】:

  • 您需要在 xmlAsJson.elements.map(…) 调用周围使用 Promise.all(),然后使用与在第一个条件分支中使用的相同的模式分配给 elements
【解决方案2】:

你可以使用“Promise.all”...

对于一个简单的数组,你可以在数组上映射一个函数: 该函数为每个元素的“新值”返回一个承诺。 如果你使用 Bluebird Promise,你甚至可以返回 Promises 和普通值的混合。 (无需在“Promise.resolve”中包装普通值) 然后你将 Promise 数组传递给“Promise.all()”,它会等待它们全部完成。

要转换树形数据结构(如 JSON),您需要做同样的事情,但需要递归。树中的每个节点都会使用“Promise.all”来等待其所有的 child-nodes=,而根节点只会在树中的每个节点都已解析后才“解析”。

请注意,“Promise.all”将同时运行所有 ASYNC 函数。如果你不想这样,你可以改用“Promise.mapSeries”,它做同样的事情,但它在开始下一个之前等待每个异步函数。如果您有大量数据并且不想同时启动太多同步异步函数,这可能会更好。

【讨论】:

  • 谢谢,这是我一直在寻找的答案。清楚地解释要做什么,谢谢。
猜你喜欢
  • 2011-05-05
  • 2019-08-23
  • 2018-09-30
  • 1970-01-01
  • 2012-01-17
  • 2020-05-31
  • 2016-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多