【问题标题】:Typescript/JS recursive promisesTypescript/JS 递归承诺
【发布时间】:2020-10-13 06:33:06
【问题描述】:

我正在学习 Javascript,但我一直在使用 Promises。

我正在尝试从 API 文档中创建一个树状结构,其中 JSON 中的 $ref 键被替换为位于文件中其他位置的 API 对象。这需要相当同步地发生,在我遍历 API 对象的键时,当我找到一个 $ref 时,它会在 JSON 中查找并替换。

例如

"apiStorageVersion": {
    "description": "...",
    "properties": {
      "apiVersion": {
        "description": "...",
        "type": "string"
      },
      "kind": {
        "description": "...",
        "type": "string"
      },
      "metadata": {
        "$ref": "#/definitions/apiMetaData",
        "description": "..."
      },
      "spec": {
        "$ref": "#/definitions/apiSpec",
        "description": "..."
      },
      "status": {
        "$ref": "#/definitions/apiStatus",
        "description": "..."
      }
    }
}

我从这个函数开始,它获取我认为是父对象的 API 对象列表,从某种意义上说,这些对象是 API 中更重要的对象。 Definitions 是文件的内容,包含所有 API 对象。

function fillObjectTree(parents: string[]) {
    console.log(parents);
    Object.keys(definitions).map(apiTitle => {
        // if the apiTitle is part of the parents list than we process it
        if (parents.includes(apiTitle)) {
            // Read the children and see if any references are part of the parent
            let par = readChildren(definitions[apiTitle])
            par.then(function (vals) {
                // Do something with values
            })
        }
    })
}

下一步是读取此 API 对象的属性并查找 $ref 键。

function readChildren(definition: { properties: any; }) {
    return new Promise((resolve, reject) => {
        // Get the properties of the definition
        let props = definition.properties;
        // Properties are not always present on an object.
        if (props) {
            Object.keys(props).map(propName => {
                Object.keys(props[propName]).map(elem => {
                    if (elem.includes("$ref")) {
                        // locationURL = the full url for the reference
                        let locationURL: string = props[propName][elem];
                        // returns the needed value for the URL based on the regex
                        let partialURL: string = locationURL.match('(?<=(\#\/.*\/)).*')[0];
                        readReference(partialURL).then((body) => {
                            console.log(body);
                            delete definition.properties[propName];
                            definition.properties[propName] = body;  
                        });
                    }
                })
            })
            resolve(definition);
        } else {
            resolve(definition);
        }
    });
}

找到引用时,会调用第二个函数,在当前文件中查找该对象。

function readReference(apiTitle: string) {
    return new Promise((resolve, reject) => {
        // Check all the definitions and find a match
        Object.keys(definitions).map(apiDef => {
            if (apiTitle === apiDef) {
                readChildren(definitions[apiDef]).then((body) => {
                    resolve(body);
                })
            }
        })
    })
}

所以出了什么问题? 好吧,操作顺序似乎与我想要发生的不匹配。对象在 JSON 中没有被替换,执行时也没有等待。我宁愿不使用 await 或 async,但尽可能将其保持在基线 Promises 中。

【问题讨论】:

  • 一些关于一般 Promise 用法的快速提示:1. 永远不要使用 new 创建 Promise,除非你想“承诺”一些基于回调的异步函数 2. 改用 Promise 链,这意味着你应该始终return 你的承诺,尤其是在then 3. 等待一系列承诺完成(如在.maps 中)使用Promise.all(...list of promises...)

标签: javascript typescript promise


【解决方案1】:

readChildren 将同步执行,直到它到达这个块:

readReference(partialURL).then((body) => {
  console.log(body);
  delete definition.properties[propName];
  definition.properties[propName] = body;  
});

readReference 将返回一个承诺,因此它会获得承诺,然后安排 then 中的任何内容在未来某个时间发生。然后函数继续,最终调用resolve(definition);,然后退出函数。这发生在 then 中的任何内容之前。

要让resolve(definition); 发生在其他所有事情之后,只需将它也放入then 块中。

编辑:上述解决方案无法处理地图。

处理异步结果列表:

const promises = list.map(element => {
  return someAsyncFunction(element);
});

Promise.all(promises)
  .then(results => {
    ... do stuff with the results
  });

顺便说一句,如果您使用非常出色的 async/await 语法,所有这些都会变得平淡无奇。推理排序变得容易得多。

【讨论】:

  • 这不会停止我的循环吗?我所拥有的是可以有多个引用,我想返回 apiDef 并替换所有引用。
  • 更新了答案。
猜你喜欢
  • 1970-01-01
  • 2014-02-02
  • 2014-02-04
  • 1970-01-01
  • 2018-05-29
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
相关资源
最近更新 更多