为每个人返回Promise

时间:2017-03-21 13:44:27

标签: foreach promise

我正在Node.js中开发一个系统,情况是这样的:我有一个Promise,它返回一个Id列表,并且返回Promise(然后)我调用另一个需要执行查询的方法对于每一个在第一种方法中返回的项目。

最好的方法是什么?

我的代码是这样的:

  checkLastPosition(list) {
    let returnList = new Array();
    var actualDate = new Date();
    list.forEach(function (item) {
        return new Promise((resolve, reject) => {
            pool.getConnection(function (err, connection) {

                if (err)
                    reject(err);

                let sql = ' select * from posicao loc';
                sql += ' where veiculoid = ?';
                sql += ' and loc.dataHora = (select max(dataHora) from posicao where veiculoId = loc.veiculoId)';
                sql += ' order by loc.veiculoid, datahora desc';

                connection.query(sql, item.veiculoid, function (err, rows) {

                    connection.release();

                    if (err)
                        reject(err);

                    resolve(rows[0]);
                });
            });
        }).then(result => {


            if (!result) {
                returnList.push(item.veiculoId);
            } else {
                if (new Date(result.dataHora.toLocaleString()) <= actualDate.setMinutes(actualDate.getMinutes() - 10)) {
                    returnList.push(item.veiculoId);
                }
            }
        });

    }, this);
}

2 个答案:

答案 0 :(得分:3)

首先,将list.forEach()调用转换为list.map()。使用map(),您可以构建一个承诺数组。每个promise都包含查询结果。

将此承诺列表保存在名为queries的变量中。然后使用Promise.all(),当queries中的所有承诺得到解决或至少有一个被拒绝时,它将产生已解决/拒绝的承诺。

这样做,您可以将then调用附加到Promise.all(),解析回调将接收包含查询结果的数组。在这里,您可以遍历结果,构建您的returnList数组并返回它。

returnList将被then()包含在一个承诺中,此承诺将返回给checkLastPosition方法的调用者:

checkLastPosition(list) {
    let queries = list.map(function (item) {
        return new Promise((resolve, reject) => {
            pool.getConnection(function (err, connection) {
                if (err) reject(err);

                let sql = ' select * from posicao loc';
                sql += ' where veiculoid = ?';
                sql += ' and loc.dataHora = (select max(dataHora) from posicao where veiculoId = loc.veiculoId)';
                sql += ' order by loc.veiculoid, datahora desc';

                connection.query(sql, item.veiculoid, function (err, rows) {
                    connection.release();
                    if (err) reject(err);

                    resolve(rows[0]);
                });
            });
        });
    }, this);

    return Promise.all(queries).then(results => {
        let returnList = new Array();
        var actualDate = new Date();
        results.forEach(result => {
            if (!result) {
                returnList.push(item.veiculoId);
            } else {
                if (new Date(result.dataHora.toLocaleString()) <= actualDate.setMinutes(actualDate.getMinutes() - 10)) {
                    returnList.push(item.veiculoId);
                }
            }
        });
        return returnList;
    });
}

答案 1 :(得分:0)

我假设您使用的是mysqljs

我不是创建每个执行一个SQL查询的几个promise,而是创建一个promise,让SQL查询在tf.strided_slice中执行检查整个输入列表。这样,您只需查询一次数据库。

我认为你也遇到in的问题,因为在这个表达式中你真的修改了这个变量:

actualDate

每次评估表达式时,它会从中减去10分钟,因此您最终会与-10,-20,-30,......分钟进行比较。

以下是一些未经测试的代码,说明了这个想法:

actualDate.setMinutes(actualDate.getMinutes() - 10)

请注意,我在查询中不再使用checkLastPosition(list) { var actualDate = new Date(); // Be careful: setMinutes will mutate the variable -- don't repeat it: actualDate.setMinutes(actualDate.getMinutes() - 10); return new Promise((resolve, reject) => { pool.getConnection(function(err, connection) { if(err) reject(err); let sql = ' select * from posicao loc'; sql += ' where veiculoid in (' + // use IN operator and inject escaped list of ID values list.map(item => connection.escape(item.veiculoid)).join(',') + ')'; sql += ' and loc.dataHora = (select max(dataHora) from posicao where veiculoId = loc.veiculoId)'; sql += ' order by loc.veiculoid, datahora desc'; connection.query(sql, function(err, rows) { // no more bound variables connection.release(); if(err) reject(err); resolve(rows); // all rows }); }); }).then(result => { // Identify which records should be excluded, and make a Set of them, for faster lookup const toExclude = new Set(result.filter( record => new Date(record.dataHora.toLocaleString()) > actualDate ) .map( record => record.veiculoid ) ); // Take the original list of items, and exclude the ones from it according to that Set: return list.map(item => item.veiculoid).filter(veiculoid => !toExclude.has(veiculoid)); }); } ,与动态ID列表一样,您需要传递相同数量的ID。正如我在文档中读到API内部使用?一样,我只使用了该函数而不是connection.escape()