【问题标题】:promise not resolving before return承诺返回前不解决
【发布时间】:2018-02-15 09:43:51
【问题描述】:

我正在解析一组文件并发布到数据库。作为其中的一部分,我需要保留文件中的数据总数,以及成功插入数据库的记录的计数。承诺不会等待所有记录写入数据库。

我正在寻找 parserResults 方法以将 testResults 返回给调用 .reduce。它确实将其传回,但 insertSuccess = 0。

我放入了一些控制台日志以查看它在做什么,并且 finalResult 在递增的 insertSuccess 计数器递增之前显示在控制台上。

Console.log 结果

In parseresults ui-results-11705.json
In parseresults ui-results-14981.json
In parseresults ui-results-14982.json
In parseresults ui-results-28274.json
In parseresults ui-results-368.json

finalResult =  { insertSuccess: 0,
  insertFailed: 0,
  testPassedCount: 2,
  testFailedCount: 3 }

insertSuccess 1
insertSuccess 2
insertSuccess 3
insertSuccess 4
insertSuccess 5

这是调用将解析文件的函数的代码

 matches.reduce(function (p, val) {
    return p.then(function () {
      console.log('p', p);
      return parser.parseResults(val);
    });
}, Promise.resolve()).then(function (finalResult) {
     console.log('finalResult = ', finalResult);
}, function (err) {
     console.log('error in reduce', err);
});

这里是被调用的方法

protractorParser.prototype.parseResults = function (fileName) {
    return new Promise((resolve, reject) => {
        console.log('In parseresults', fileName);
        var currentFile = './testing/results/' + fileName
        json.readFile(currentFile, function (err, obj) {
            if (err != null) {
                console.log('error reading file', err);
                reject(err);
            } else {
                resolve(obj);
            }
        });
    }).then(function (obj) {
        var results = [];


        for (var suite in obj) {
            var specs = obj[suite].specs;
            for (let i = 0; i < specs.length; i++) {
                const assert = specs[i];
                const tcR = /TC[\d]+/;
                const tc = assert.description.match(tcR);

                let Passed = 1;
                let Message = '';
                let Stack = '';
                if (assert.failedExpectations.length) {
                    const expectation = assert.failedExpectations[assert.failedExpectations.length - 1];
                    Passed = 0;
                    Message = expectation.message;
                    Stack = expectation.stack.split('\n')[1].trim();
                    testResults.testFailedCount++
                } else {
                    testResults.testPassedCount++
                }
                if (tc != null) {

                    const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
                    const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
                    results.push(promise.then(() => {

                        testResults.insertSuccess++;
                        console.log('insertSuccess', testResults.insertSuccess);

                    },
                        err => { console.log('… failed', err); throw err; }
                    ));

                } else {
                    console.log('no test case found for test: ' + assert.description + ' -- skipping');
                    // I don't think you want to `throw err` here, right?
                }
            }
        }
        return (Promise.all(results), testResults);
    });
};

我在代码中尝试了几种不同的场景,但似乎无法弄清楚。任何帮助将不胜感激。 谢谢 克里斯汀

【问题讨论】:

  • reduce 不是一个承诺感知函数,即它不关心你返回什么,它只是将它传递给下一次迭代而不是等待。
  • return (Promise.all(results), testResults); 仅返回 testResults(参见 comma operator) - 这不是承诺,因此不会等待 results.push(promise.then(() =&gt; { 中的承诺
  • @PatrickEvans - 这看起来像是使用.reduce() 对一系列返回承诺的异步操作进行排序的正确方法。问题似乎是 parseResults() 没有返回承诺,因为 return 语句搞砸了。
  • 因为testResults 看起来是全局的 - 或者至少在更高(通用)范围内,无论如何都不需要返回它
  • @JaromandaX - 也许他们不需要返回testResults,但他们使用的其他代码希望它是.reduce() 循环的finalResult,因此可以返回它来制作发生这种情况。

标签: javascript arrays promise


【解决方案1】:

parseResults() 没有正确返回承诺,因此您在 .reduce() 循环中的 p.then() 不会等待任何内容。

改变这个:

return (Promise.all(results), testResults);

到这里:

return Promise.all(results).then(() => testResults);

您使用的代码:return (Promise.all(results), testResults); 仅返回 testResults,而不是承诺。我认为您想要知道何时完成所有承诺,然后将 testResults 设为已解决的值。为此,您在Promise.all() 上使用.then(),然后从该.then() 处理程序返回testResults。这将返回一个 promise,其解析值为 testResults

仅供参考,您可能根本不需要这样做,因为testResults 似乎是一个更高范围的变量,您可以直接引用它。如果您愿意这样做,那么您只需更改为:

return Promise.all(results);

然后,不要在最终的.then() 处理程序中使用finalResult,只需直接引用更高范围的testResults 变量即可。


仅供参考,一个更简洁的实现可以传入一个对象,循环的每次迭代都返回并传递到下一次迭代,因此根本没有对更高范围变量的引用,并且一切都更加自包含。然后,您将使用我向您展示的第一种返回类型,但您将返回传入的对象,而不是更高范围的对象。

【讨论】:

  • 再次感谢。刚查了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 2021-05-25
  • 2015-06-24
  • 1970-01-01
  • 2013-05-15
  • 1970-01-01
相关资源
最近更新 更多