【问题标题】:Promise returned from method gets undefined从方法返回的 Promise 未定义
【发布时间】:2016-02-18 10:45:11
【问题描述】:

我有一个接受函数作为回调参数的方法。外部方法和回调函数都返回我收集到数组的 Promise,等待它们被 Q.all 解决。

function eval() {
    var colReadPromisses = [];

    config.mongodb.colls.forEach(function (collName) {

        var outer = mongo.readCollection(collName,
                function (jsonData) {
                    var prom = es.pushItemToES(jsonData, esIndexName, collName, i);
                    colReadPromisses.push(prom);
                });
        colReadPromisses.push(outer);
    });

    return Q.all(colReadPromisses);
}

现在,内部回调方法被多次调用,并且需要一些时间来处理所有这些。在处理它们时,从“readCollection”方法返回的承诺变得“未定义”,导致“Q.all(colReadPromisses);”解决。

所以我的两个问题是为什么 nodejs 无法跟踪从“readCollection”方法返回的承诺,我该如何避免这种情况?

感谢您的回复!

【问题讨论】:

  • 您缺少两个 } 以使其成为有效功能...请编辑您的代码,以便我们可以看到您实际在做什么 - 即使我猜到它们应该放在哪里,代码错误
  • 你说inner callback method is called many times - PER readCollection 可能是次要的吗?
  • 您还说 readCollection 和“回调函数”返回承诺......这些承诺如何/何时解决? (你的意思是回调函数内部调用的函数返回一个承诺吗?因为回调函数不返回一个承诺 - 它根本不返回任何内容)
  • 如果,正如您的问题所暗示的那样,readCollection 的回调在每个循环中被多次调用(即,不仅仅是每个循环一次),重要的是要知道您的函数 mongo.readCollection正在努力知道这是否可能 - 我有一个解决方案,但它做出了太多的假设来发布
  • 是的,每个“readCollection”都会调用多次。 'readCollection' 本身在​​调用时返回 Promise 并尝试读取 mongo 集合。在每次读取记录时,都会调用该内部回调。此回调将行推送到“pushItemToES”中的 Elastic Search,这也返回了 Promise。当 mongo 触发文档读取事件的“结束”时,“readCollection”的承诺正在其中解决。 'pushItemToES' 还解决了它在弹性搜索推送成功后的承诺。正如你所看到的,我提到'pushItemsToES'返回承诺,而不是回调本身,当然......

标签: javascript node.js promise


【解决方案1】:

我假设您想在返回的承诺中获取所有 readCollection 和 pushItemToES 的结果

function eval() {

    return Q.all(config.mongodb.colls.map(function (collName) {

        var pushPromisses = [mongo.readCollection(collName, function (jsonData) {
            pushPromisses.push(es.pushItemToES(jsonData, esIndexName, collName, i));
        })];

        return pushPromisses[0] // once the outer promise resolves
        .then(function() {
            return Q.all(pushPromisses); // wait for them all (including the outer)
        });

    }));
}

解析后返回的promise,将解析为二维数组

  • [0][0] 将是 mongo.readCollection(colls[0]) 的结果
  • [0][1..n] 将是来自 readCollection(colls[0]) 的每个 pushItemToES 的结果
  • [1][0] will be the result of themongo.readCollection(colls[1])`
  • [1][1..n] 将是来自 readCollection(colls[1]) 的每个 pushItemToES 的结果

等等

如果你不需要返回的promise中mongo.readCollection的结果

function eval() {

    return Q.all(config.mongodb.colls.map(function (collName) {

        var pushPromisses = [];

        return mongo.readCollection(collName, function (jsonData) {
            pushPromisses.push(es.pushItemToES(jsonData, esIndexName, collName, i));
        }).then(function() {
            return Q.all(pushPromisses);
        });

    }));
}

在这种情况下,返回的承诺仍然是二维的,但只有 pushItemToES 的结果

  • [0][0..n] 将是来自readCollection(colls[0]) 的每个pushItemToES 的结果
  • [1][0..n] 将是来自readCollection(colls[1]) 的每个pushItemToES 的结果

我在已解决的承诺中看不到二维数组周围的任何方式 - 因为 es.pushItemToES 没有被称为“已知”(至少不是提前)次数

【讨论】:

  • 按预期工作!我实际上也不需要“pushItemToES”的任何结果。我使用承诺只是为了同步。此外,你告诉我为什么我“丢失”了从“readCollection”返回的承诺的链接,为什么在你的解决方案中使用“map”很重要?
  • map 在从其他数组创建 1:1 数组时很方便。我只是猜测您返回的承诺行为不端的原因是因为数组正在在调用 Q.all 后被回调改变 - 虽然只是猜测......
【解决方案2】:

你必须重新组织你的代码:

function eval() {
    // replace forEach with map
    var colReadPromisses = config.mongodb.colls.map(function (collName) {

           // return pushItemToES promises
            return new Promise(function(resolve) {
                mongo.readCollection(collName,
                    function (jsonData) {
                        resolve(es.pushItemToES(jsonData, esIndexName, collName, i));                   
                    });
            });

    });

    // colReadPromisses stores array of pushItemToES promises
    return Q.all(colReadPromisses);
}

【讨论】:

  • if inner callback method is called many times(我假设在外循环的每次迭代中多次)-您的代码将很快解析(在每次迭代的第一次之后)
  • 哦,我的错。你能提供更多关于readCollection函数的信息吗?回调只接收jsonData 参数?
猜你喜欢
  • 2017-09-22
  • 2016-07-19
  • 2017-10-31
  • 2020-10-03
  • 1970-01-01
  • 2018-09-21
  • 2019-09-02
  • 2023-04-11
  • 2017-12-14
相关资源
最近更新 更多