回调已被调用。但在那之前我从来没有打电话给回调。 async.parallel 中的错误? [复制]

Posted

技术标签:

【中文标题】回调已被调用。但在那之前我从来没有打电话给回调。 async.parallel 中的错误? [复制]【英文标题】:Callback was already called. But I never call callback before that. A bug in async.parallel? [duplicate] 【发布时间】:2017-12-16 14:21:56 【问题描述】:

我在网上对这个问题做了很多研究,仍然无法知道问题的原因。

问题是,当我使用异步库中的并行函数时,出现错误:

Callback was already called.

这是我的代码:(我已在出现此错误的行上发表评论)

var sendNotificationAddToMyRememberNew = function(request, response, restaurant) 

    async.parallel(
        notification_list: function (callback) 
            models.NotificationList.create(
                alert_msg: "Restaurant " + restaurant.name + " remembered.",
                payload: JSON.stringify(
                    restaurant_id: restaurant.id,
                    restaurant_name: restaurant.name,
                    restaurant_image: restaurant.image
                ),
                type: constants.NOTIFICATION_TYPE.RESTAURANT_REMEMBERED,
                platform_type: constants.MOBILE_PLATFORM_TYPE.ALL,
                status: constants.NOTIFICATION_STATUS.SENT,
                device_token: null,
                device_arn: null,
                schedule_time: moment.utc(),
                customer_id: request.token.customer_id,
                customer_email: request.token.email,
                created_date: moment.utc(),
                updated_date: moment.utc()
            ).then(function(notificationList)
                callback(null, notificationList);
            ).catch(function(error)
                callback(error);
            );
        ,
        badge_count: function(callback) 

            models.CustomerBadgeCount.findOrCreate(
                where: 
                    customer_id: request.token.customer_id
                ,
                defaults: 
                    badge_count: 1,
                    customer_id: request.token.customer_id,
                    created_date: moment.utc(),
                    updated_date: moment.utc()
                
            ).spread(function (badgeCount, created) 
                if(!created)
                    badgeCount.update(
                        
                            badge_count: badgeCount.badge_count + 1,
                            updated_date: moment.utc()
                        ,
                        
                            fields:[
                                "badge_count",
                                "updated_date"
                            ]
                        
                    ).then(function(badgeCount) 
                        callback(null, badgeCount);
                    ).catch(function (error) 
                        callback(error); // Getting error of callback here
                    );
                else
                    callback(null, badgeCount)
                
            ).catch(function (error) 
                callback(error);
            );

        ,
        devices: function(callback) 
            models.CustomerDeviceTokens.findAll(
                where: 
                    customer_email: request.token.email
                
            ).then(function(devices) 
                callback(null, devices);
            ).catch(function(error) 
                callback(error);
            );
        
    , function(error, results)

        if(error) 
            Logger.logDbError(error,request);
            return console.log(error);
        
        //callback function
        console.log("-------------------------------------------------------");
        console.log("Notification List: " + JSON.stringify(results.notification_list, null, 4));
        console.log("badge_count: " + JSON.stringify(results.badge_count, null, 4));

        if(results.devices && result.devices.count > 0) 
            results.devices.forEach(function(device) 
                console.log("device_arn: " + device.device_arn);
            , this);
        
    );


【问题讨论】:

不要将 async.js 与 Promise 一起使用。普通的Promise.all 要容易得多。 @Bergi 这个问题不重复。我已经解决了这个问题。请看我的回答。 副本解释了difference between .then(…, …) and .then(…).catch(…),这是导致callback 被调用两次的原因。 如果你觉得这个问题是重复的,那么请删除它。因为我不能删除它,因为这个问题已经有了答案。 @Bergi 对不起,我忘了在上面的评论中提到你的名字。请阅读。 【参考方案1】:

如果callback(null, badgeCount) 抛出错误,就会发生这种情况(如果最终回调由于某种原因抛出错误,就会发生这种情况)。

在这种情况下发生的情况是调用了 .catch 处理程序,在其中您再次调用 callback,导致 “已调用” 消息。

为了防止这种情况(或者更确切地说,为了捕获这些错误),您不应使用 .catch,而应使用 .then 的两个参数版本:

.then(function(badgeCount) 
  callback(null, badgeCount);
, function (error) 
  callback(error);
);

(对于代码中在 async 操作中使用 .then().catch() 的所有其他位置类似)

【讨论】:

好答案!!!!!!但我已经想通了。我会再发一个。感谢您的回答和您的时间。【参考方案2】:

我在我的代码中使用了findOrCreate sequelize 方法。 findOrCreate 的原始语法是:

model.SomeModelName.findOrCreate(
    ....
    ....
).spread(function(data, created) 

).fail(function(err) 

);

正如您在上面的代码中看到的那样,.spread() 后面应该跟着.fail(),但在我的代码中,我使用了.spread(),后面跟着.catch()。 因此,两个块都已执行,因此 回调被调用了两次

【讨论】:

这可能是您在then 中获得异常的方式,但这不是实际问题。

以上是关于回调已被调用。但在那之前我从来没有打电话给回调。 async.parallel 中的错误? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

ES6深入浅出-9 Promise 3 视频-1.回调与回调地狱

Java 回调函数

神马是回调函数?

回调函数

一个简单的java回调函数的实现

回调函数(callback)是什么?