【问题标题】:Promise in Node not working - .then is undefined节点中的承诺不起作用 - .then 未定义
【发布时间】:2017-11-04 10:28:38
【问题描述】:

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

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

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

我的代码 sn-p 如下:

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,它看起来确实像一个 Promise 链。当然,result 变量也存在,所以这不是 DB 命令的问题。

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

如果需要更多信息,请告诉我。

【问题讨论】:

  • 你没有从updateAllUnreadNotifications返回任何东西。添加return userModel.aggregate([ ... ]);
  • 嘿伙计,感谢您指出这一点。我以为我的“return new Promise”行会涵盖它,但想一想,那是针对 .map 循环的。你介意把我引向正确的方向吗?不用说,有点JS新手。
  • @ShayanKhan 编辑您的问题。我没有看到 userModel.aggregate([ 对应的结束 ] 括号
  • 您似乎有一些语法错误,这是您使用的确切代码吗?
  • 我错过了 userModel.aggregate 的“函数”行。现在,它已经完成了。我很抱歉。

标签: javascript node.js promise


【解决方案1】:

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

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

    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'
        });
    });

【讨论】:

  • 不错的一个。让我马上试一试,然后回复你
  • 像魅力伴侣一样工作。非常感谢!
【解决方案2】:

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'
    });
});

【讨论】:

  • 感谢贝尔吉的回答。我也会试试这个(如你所见,另一个答案对我有用)。但作为一个学习练习,我将通过你的代码,以便我能更多地理解 Promises。每次我认为我已经完成了 Promise 时,我都会迷失方向。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-19
  • 1970-01-01
  • 2021-10-24
  • 2018-10-11
  • 2016-10-18
  • 2019-07-14
  • 1970-01-01
相关资源
最近更新 更多