【问题标题】:iteration through an array and then calling .reduce on an array with promise遍历一个数组,然后在一个带有 promise 的数组上调用 .reduce
【发布时间】:2018-08-16 03:20:54
【问题描述】:

我知道这可能是一个非常基本的问题,但我只是在学习并且被卡住了。我无法思考如何在这里做我需要做的事情。

我有一个名为 RallyResults 的数组

rallyResults [ { ExecutionType: 'ci',
    dataArray:
     [ [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object] ] },
    { ExecutionType: 'regression',
    dataArray: [ [Object], [Object], [Object], [Object], [Object], [Object] ] },
     { ExecutionType: 'ci',
    dataArray: [ [Object], [Object], [Object], [Object], [Object], [Object] ] }
  { ExecutionType: 'regression',
    dataArray: [ [Object], [Object], [Object], [Object], [Object] ] } ]

我需要遍历 rallyResults 数组,当 rallyResults.ExecutionType 为“Regression”时,我需要遍历 rallyResults.dataArray,并对 rallyResults.dataArray 中的每个项目进行一些处理。我只想在所有的 rallyResults.dataArray 中的项目都处理完后才返回。

我已经为代码尝试了几次不同的迭代,但都没有成功。这就是我现在编码的内容。

ProcessDatabase.prototype.ckForAddToSet = function (rallyResults) {
    return new Promise((resolve, reject) => {
        var module = this;
        console.log('In ckForAddToSet')
        //console.log('rallyResults', rallyResults);


        rallyResults.forEach(function (entry) {
            //console.log('in ckForAddToSetentry', entry);
            if (entry.ExecutionType == 'regresstion' || entry.ExecutionType 
                                               == 'smoke') {
                 entry.dataArray.reduce(function (p, val) {
                    return p.then(function () {
                        return module.addTestCaseToSet(val);
                    });
                }, Promise.resolve()).then(function (addResults) {
                    console.log('addResults ', addResults);
                }, function (err) {
                    console.log('error in reduce in ckForAddToSet', err);
                });
            }
        });
    })
}

它开始遍历 rallyResults 并找到 rallyResults.ExecutionType = 'regression' 的第一项,调用 entry.dataArray.reduce。

它像我需要的那样通过 module.addTestCaseToSet 方法处理所有 dataArray 记录,然后返回并打印 console.log('addResults ', addResults);来自 .reduce 中的 promise.resolve。

然后停止。

我无法弄清楚如何让它继续遍历剩余的 rallyResults 项目。当它从 .reduce 中的 module.addTestCaseToSet 方法返回时,我确实尝试过解决,但这结束了整个过程并且仍然没有处理所有的 rallyResult 项目。

这里是 addTestCaseToSet 方法

ProcessDatabase.prototype.addTestCaseToSet = function (data) {
    return new Promise((resolve, reject) => {

        console.log('in addTestCaseToSet', data);
        var dataValues = {
            data: [],
            tcvalues: []
        }
        dataValues.data = data;
        //console.log('dataValues.data', dataValues.data);
        rallyApi.getTestCase(dataValues.data.TestCaseId).then((values) => {

            dataValues.tcvalues = values;
            //console.log('dataValues = ',dataValues);
            resolve(dataValues);
        }, err => { reject('… failed finding testCase ' + dataValues.data.TestCaseId, err); });


    }).then(function (dataValues) {
        var module = this;
        var addToSet = [];
        const promise = new Promise((resolve, reject) => {
            rallyApi.addTestCaseToSet(dataValues.tcvalues.ObjectID, dataValues.tcvalues.Ref, dataValues.data.TsObjectId, dataValues.data.TsRef).then((results) => {
                addToSet = results;
                resolve(addToSet);
            }, (err) => { reject(err); });
        });

        results.push(promise.then(() => {
            addResults.push(addToSet);
        },
            err => { console.log('… failed', err); throw err; }
        ));
        return Promise.all(results).then(() => addResults);

    })
}

module.addTestCaseToSet 的结果如下:

addResults  [ { tsRef: 'https://rally1.rallydev.com/slm/webservice/v2.0/testset/203724645320',
    tcRef: 'https://rally1.rallydev.com/slm/webservice/v2.0/testcase/152495978580',
    action: 'added' },
  { tsRef: 'https://rally1.rallydev.com/slm/webservice/v2.0/testset/203724645320',
    tcRef: 'https://rally1.rallydev.com/slm/webservice/v2.0/testcase/192221079432',
    action: 'added' },
  { tsRef: 'https://rally1.rallydev.com/slm/webservice/v2.0/testset/203724645320',
    tcRef: 'https://rally1.rallydev.com/slm/webservice/v2.0/testcase/128260769452',
    action: 'added' }]

非常感谢您的帮助。

【问题讨论】:

  • module.addTestCaseToSet() 返回什么?
  • 我在最初的帖子中添加了从 module.addTestCaseToSet 返回的内容。放在这里太长了。
  • 我真的只想知道module.addTestCaseToSet(val);是否返回。
  • 哦,好的。我认为确实如此。我说我认为是因为那是我的意图。但是因为我对此真的很陌生。它可能没有正确编码。我也在最初的帖子中添加了该方法。
  • 好的,ProcessDatabase.addTestCaseToSet() 肯定会返回一个承诺,尽管代码应该会大大简化。您选择连续调用该方法(使用.reduce() 模式)是否有特殊原因?如果这些调用可以并行进行,那么代码将进一步简化。

标签: javascript arrays promise


【解决方案1】:

ProcessDatabase.addTestCaseToSet() 和 ProcessDatabase.ckForAddToSet() 都不需要明确的 new Promise()。有很多机会返回自然发生的承诺。

ProcessDatabase.addTestCaseToSet() 看起来过于复杂,并且在addToSet/addResults/results 领域相当混乱。

ProcessDatabase.addTestCaseToSet() 最简单的写法如下:

ProcessDatabase.prototype.addTestCaseToSet = function(data) {
    return rallyApi.getTestCase(data.TestCaseId)
    .then(values => rallyApi.addTestCaseToSet(values.ObjectID, values.Ref, data.TsObjectId, data.TsRef))
    .catch(err => {
        throw new Error('… failed adding testCase ' + data.TestCaseId + ' (' + err.message + ')');
    });
};

在对ProcessDatabase.addTestCaseToSet() 的重写中,做了以下假设:

  • rallyApi.addTestCaseToSet() 返回结果或结果承诺(不是承诺数组)。
  • 不需要任何副作用,并且通过返回的 Promise 传递结果符合函数的要求。

在ProcessDatabase.ckForAddToSet() 中,模式rallyResults.forEach(function(entry) => { ...; entry.dataArray.reduce(...) }); 仅部分满足串行调用module.addTestCaseToSet(data) 的目标。为了完全实现该目标,外部循环 (.forEach()) 需要替换为与内部循环相同的 .reduce() 模式。

试试这样的:

ProcessDatabase.prototype.ckForAddToSet = function(rallyResults) {
    var module = this;
    return rallyResults
    .filter(entry => entry.ExecutionType === 'regression' || entry.ExecutionType == 'smoke')
    .map(entry => entry.dataArray)
    .reduce((promise0, dataArray) => {
        return promise0.then(arr0 => {
            return dataArray.reduce((promise1, data) => {
                return promise1.then(arr1) => {
                    return module.addTestCaseToSet(data)
                    .then(result1 => {
                        arr1.push(result1);
                        return arr1;
                    });
                });
            }, Promise.resolve([]))
            .then(result0 => {
                arr0.push(result0);
                return arr0;
            });
        });
    }, Promise.resolve([]))
    .then(addResults => {
        console.log('addResults ', addResults); // addResults will be an array of arrays.
    }, err => {
        console.log('error in reduce in ckForAddToSet', err);
    });
};

可能还有一些工作要做,但这应该更接近你想要的。

【讨论】:

  • 非常感谢漫游者!这绝对是一个更干净的实现
  • 克里斯汀不用担心。我希望它对你有好处。出于兴趣,我离真正有效的东西有多近?
猜你喜欢
  • 2013-06-11
  • 1970-01-01
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
  • 2017-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多