循环内的异步承诺

Async promises inside loop

我知道这是一个有很多信息的话题,但我仍然无法解决这个问题。

我正在使用连接到 mysql 服务器的 NodeJs,我有一个数组,我需要迭代数组并对数据做一些事情,问题是我需要查询mysql 服务器,但我需要 for 循环等到我得到查询结果,我已经尝试了很多东西,现在我正在尝试使用 .each 蓝鸟方法,但仍然无法正常工作,这是我的代码。

初始函数为Notification.getByUser

提前致谢

'use strict';
var Promise = require("bluebird");

module.exports = function(Notifications) {
  Notifications.execute = function(sql, itemId) {
    return new Promise((resolve, reject) => {
      this.dataSource.connector.execute(sql, (e, result) => {
        console.log('-----RESULT----', itemId);
        console.log(result);
        console.log('-----ERROR-----', itemId);
        console.log(e);
        if (result.length === 0) {
          resolve(false);
        } else {
          resolve(true);
        }
      });
    });
  };
  Notifications.isMatching = function(item, user, type) {
    return new Promise((resolve, reject) => {
      console.log(type, item, user);
      if (item !== null) {
        if (item !== user) {
          resolve(false);
        }
      }

      resolve(true);
    });
  };
  Notifications.getByUser = function(userId, isZolver, countryId, cityId, userState, cb) {
    var where = { status: 1 };
    var plainText = '';
    var items = Notifications.find({ where });
    Promise.each(items, item => {
      return Notifications.isMatching(item.isZolver, isZolver, 'isZolver')
        .then(() => {
          Notifications.isMatching(item.cityId, cityId, 'cityId');
        })
          .then(() => {
            if(item.extraCondition !== null && item.extraCondition !== '') {
              var sql = item.extraCondition.replace(/:user_id/g, userId);
              // console.log(sql);
              Notifications.execute(sql, item.id)
                .then(render => console.log('extraCondition', render));
            } else {
              console.log('extraCondition', true);
            }
          });
    }).then(res => {
      // console.log('res del loop', res);
    });
    cb(null, 'ok');
  };
};

您的代码存在几个问题:

  • 为了链接承诺,您必须确保 return 您在 then 回调中创建的承诺

  • 您不需要为立即可用的结果创建承诺 (isMatching)

  • then 回调总是在承诺实现时执行。你是否做 resolve(false) 并不重要:即使承诺的值为 false 这仍然会使承诺实现并触发 then 回调。

您的代码中有一些未知数,例如 Notifications.find,以及您正在执行哪种 SQL:是否 return 结果集,如果是,您是否会有兴趣获得该结果而不是仅仅解析为布尔值吗?

无论如何,这里有一些应用更正:

'use strict';
var Promise = require("bluebird");

module.exports = function(Notifications) {
    Notifications.execute = function(sql, itemId) {
        return new Promise((resolve, reject) => {
            this.dataSource.connector.execute(sql, (e, result) => {
                console.log('-----RESULT----', itemId);
                console.log(result);
                console.log('-----ERROR-----', itemId);
                console.log(e);
                resolve (result.length !== 0); // The `if ... else` is overkill
            });
        });
    };

    //You don't need isMatching to return a promise
    Notifications.isMatching = function(a, b) {
        return a === null || a === b;
    };

    Notifications.getByUser = function(userId, isZolver, countryId, cityId, userState) {
        var where = { status: 1 };
        var items = Notifications.find({ where })
            // use filter() to limit the items to those you want to execute the SQL for
            .filter(item => {
                return Notifications.isMatching(item.isZolver, isZolver)
                    && Notifications.isMatching(item.cityId, cityId)
                    && item.extraCondition !== ''
            });
        // Return the promise! (don't go back to the old callback system!)
        return Promise.each(items, item => {
            var sql = item.extraCondition.replace(/:user_id/g, userId);
            // Return the promise!
            return Notifications.execute(sql, item.id);
        }).then(res => {
            console.log('res del loop', res);
        });
    };
};

注意Notifications.getByUser的签名没有最后的回调参数:一旦你开始使用promise,你应该继续使用它们,所以当你调用这个函数时,调用结果的then方法就像你会为任何承诺做的那样:

 Notifications.getByUser( .......arguments....).then( function () {
     // do something...
 });