【问题标题】:Recursively modifying an object with Promises使用 Promises 递归修改对象
【发布时间】:2016-10-20 08:47:40
【问题描述】:

我正在尝试遍历 ElasticSearch 的结果并通过替换数组中的项目来修改原始对象。我快完成了,但是 Promise 被解决了不止一次,让我没有可用的结果。

我正在使用source.included = Array.map() 将原始数组替换为函数调用的结果,它几乎可以正常工作。保持对象的原始结构和included 数组中的顺序很重要,这就是我决定尝试这种方法的原因。我试图将自己定位在this example,但 Promise.all() 不知何故无法解决这些承诺。有什么想法吗?

let source = {
  title: '1',
  included: [{
    _id: 'new',
    _type: 'mytype'
  }]
}

function recursiveGet (source) {
  return new Promise((resolve, reject) => {
    client.mget({
      body: {
        docs: docsToFetch
      }
    })
    .then(response => {
      return source.included.map(item => {
        return somethingAsync(response)
      })
    })
    .then(promises => {
      Promise.all(promises)
        .then(resolved => {
          source.included = resolved.map(doc => {
            if (doc.included && !doc.resolved) {
              resolve(recursiveGet(doc))
            } else {
              resolve(doc)
            }
          })
        })
    })
  })
}

recursiveGet(source)

【问题讨论】:

  • “但 Promise 不止一次解决” 不,不是。根据定义,Promise 只会被解决(技术上,解决)一次。
  • 我只在 Angular 中使用 $q 完成了此操作。诀窍是将延迟对象(承诺)传递给您的递归函数。
  • 请提供准确的输入、所需的输出和具体问题
  • “但是 Promise.all() 无法解决承诺。” 你是什么意思?你不是returnPromise.all()从上次.then()吗?

标签: javascript node.js recursion promise


【解决方案1】:

避免Promise constructor antipattern

您不能(绝不能)多次调用resolve - 在您的情况下,从map 循环中。改用这个:

function recursiveGet (source) {
  return client.mget({
    body: {
      docs: docsToFetch
    }
  }).then(response => {
    let promises = source.included.map(item => {
      return somethingAsync(response) // did you mean `item` here?
    })
    return Promise.all(promises);
  })
  .then(resolved => {
    let morePromises = resolved.map(doc => {
//                              ^^^ another loop...
      if (doc.included && !doc.resolved) {
        return recursiveGet(doc);
      } else {
        return doc;
      }
    });
    return Promise.all(morePromises).then(moreResults => {
//         ^^^^^^^^^^^ another Promise.all!
      source.included = moreResults;
      return source;
    });
  });
}

如果您不想要两个顺序循环,您还可以将每个结果处理回调直接链接到 somethingAsync 承诺。

【讨论】:

  • 太棒了,谢谢!在最后一个 .then() 中需要一个 resolve() 并因此保留反模式,但它可以工作。
  • @Patrick:不,你绝对不应该保留反模式。
  • 我已经尝试了几种方法来删除它,但是如果最后 then() 中没有 resolve(),Promise 将无法解决。
  • @Patrick:您应该完全省略new Promise 调用,以及return 最终then() 调用的返回值。当周围没有resolve 回调时,无需调用resolve。再次仔细查看我答案中代码的开头。
  • 这就是我所做的 .. 返回 client.mget 并在最后返回 source 然后,Promise 仍然没有返回到主代码。我会经历并尝试更多的东西,但它是一个很好的开始。对此感到绝望。
猜你喜欢
  • 1970-01-01
  • 2015-02-17
  • 1970-01-01
  • 2020-05-04
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多