节点中的承诺不起作用 - .then未定义

时间:2017-11-04 10:28:39

标签: javascript node.js promise

我有这个非常奇怪的问题,我的Promise的.then不起作用。错误如下:

  

TypeError:无法读取未定义的属性'then'

我称之为奇怪的原因是因为我在其他地方使用相同的结构并且它完美无缺。我还想补充说它应该做的实际行动 - 确实完成了!所以这纯粹是我的Promises被“编码”的方式的问题 - 只是语法糖。

我的代码段如下:

var updateAllUnreadNotifications = function(){
    userModel.aggregate([
        {$match:{"profileID": 123}},
        {$unwind: "$notifications"},
        {$match:{"notifications.read": false}},
        {$group: {_id:"$_id", notifications: {$push:"$notifications"}}}
        ], function(err, notifications){
             var notificationPromises = notifications.map(function(notification) {
                return new Promise(function(resolve){
                    userModel.findOneAndUpdate(
                        {profileID: 123, "notifications.id": notification.id},
                        {"notifications.$.read": true},
                        {safe: true},
                        function(err, result) {
                            if (err){
                               return;
                            } else if (result){
                                resolve(notification);
                            }
                        }
                    );
                });
            });

            return Promise.all(notificationPromises);
        });
};

updateAllUnreadNotifications()
.then(function(notifications){
    res.json({
        message: 'All is well'
    });
});

此外,我在 notificationPromises 上做了 console.log ,它看起来像一连串的Promises。当然,结果变量也存在,所以这不是DB命令的问题。

我搞砸了什么?我相信这将是一个非常明显的一个,但对于我的生活,我无法孤立它。

如果需要更多信息,请与我们联系。

2 个答案:

答案 0 :(得分:1)

您需要从promise函数返回updateAllUnreadNotifications,但您没有从该函数返回任何内容。这就是你得到这个错误的原因。

我想说更好的方法是创建一个单独的函数来处理通知并链接像这样的承诺

    var updateAllUnreadNotifications = function(){
      return new Promise(function(resolve,reject){
        userModel.aggregate([
            {$match:{"profileID": 123}},
            {$unwind: "$notifications"},
            {$match:{"notifications.read": false}},
            {$group: {_id:"$_id", notifications: {$push:"$notifications"}}}
            ], function(err, notifications){
                 if(err){ reject(err)}
                 // If got notifications then resolve
                 // notifications will be available to next then function
                 resolve(notifications)
             })
         })
      }

      var processNotifications = function(notifications) {
         var notificationPromises = notifications.map(function(notification) {
              return new Promise(function(resolve){
                 userModel.findOneAndUpdate(
                    {profileID: 123, "notifications.id": notification.id},
                     {"notifications.$.read": true},
                            {safe: true},
                            function(err, result) {
                                if (err){
                                   return;
                                } else if (result){
                                    resolve(notification);
                                }
                            }
                        );
                    });
                });

         return Promise.all(notificationPromises);
       };

    // Chain one extra then here to process notifications
    updateAllUnreadNotifications().then(processNotifications)
    .then(function(notifications){
        res.json({
            message: 'All is well'
        });
    });

答案 1 :(得分:1)

来自return回调的userModel.aggregate - cannot work - 而非updateAllUnreadNotifications功能。它确实返回undefined,您尝试在其上调用then方法。您还需要promisify

function aggregateAsync(x) {
    return new Promise((resolve, reject) => {
        userModel.aggregate(x, (err, res) => {
            if (err) reject(err);
            else resolve(res);
        });
    });
}
function findOneAndUpdateAsync(x, y, z) {
    return new Promise((resolve, reject) => {
        userModel.findOneAndUpdate(x, y, z, (err, res) => {
            if (err) reject(err);
            else resolve(res);
        });
    });
}

有了这些,你可以做到

function updateAllUnreadNotifications() {
    return aggregateAsync([
        {$match:{"profileID": 123}},
        {$unwind: "$notifications"},
        {$match:{"notifications.read": false}},
        {$group: {_id:"$_id", notifications: {$push:"$notifications"}}}
    ]).then(notifications => {
        var notificationPromises = notifications.map(notification => {
            return findOneAndUpdateAsync(
                {profileID: 123, "notifications.id": notification.id},
                {"notifications.$.read": true},
                {safe: true}
            );
        });
        return Promise.all(notificationPromises);
    });
}

updateAllUnreadNotifications().then(notifications => {
    res.json({
       message: 'All is well'
    });
});