How to optimize this Node.js + q code to prevent callback hell?

别说谁变了你拦得住时间么 提交于 2019-12-23 04:55:22

问题


I am using Q to prevent callback hell but I have reached a part of my code that I don't know how to arrange:

I am searching for scheduled messages to be delivered. For each of them, I try to send them one by one and if it could be sent, removes it from the database. The ugly part is to have a then() inside a for loop. This way I end up having nested promises instead of nested callbacks!!!! Suggestions?

appLog.debug("Looking for scheduled messages");
var messages = messageService.findScheduled()
.then(function(messages){
    appLog.debug("found [%d] stored messages",messages.length);
    for(var i = 0; i<messages.length; i++){
        messageService.send(msg.namespace, msg.message, msg.data)
        .then(function(result) {
            if (result == constants.EVENT_EMIT_SENT) {
                appLog.debug("Message [%s] sent!!!", msg._id);
                messageService.remove(msg._id)
                    .then(function(result) {
                         appLog.debug("Message deleted: [%s]", msg._id);
                    })
                    .fail(function(err) {
                        appLog.error("The message couldn't be deleted: [%s]", msg._id);
                    });

            }else if (result == constants.EVENT_EMIT_NOT_SENT_AND_NOT_STORED) {
                appLog.debug("Message [%s] not sent", msg._id);
            }

        });
    }
});

回答1:


The ugly part is to have a then() inside a for loop

No, that can happen. Though the functional programming style of promises usually leads to using .map() with a callback anyway :-) Looping is a control structure, and does require nesting (except you use exceptions for control flow, i.e. branching). What you don't have to do is to nest promises in promise callbacks, though.

I'd simplify your loop body to

function sendAndDelete(msg) {
    return messageService.send(msg.namespace, msg.message, msg.data)
    .then(function(result) {
        if (result == constants.EVENT_EMIT_SENT) {
            appLog.debug("Message [%s] sent!!!", msg._id);
            return msg._id;
        } else if (result == constants.EVENT_EMIT_NOT_SENT_AND_NOT_STORED) {
            appLog.debug("Message [%s] not sent", msg._id);
            throw new Error("Message not sent");
        }
    })
    .then(messageService.remove)
    .then(function(result) {
         appLog.debug("Message deleted: [%s]", msg._id);
    }, function(err) {
         appLog.error("The message has not been deleted: [%s]", msg._id);
    });
}

Now you can do something like

messageService.findScheduled()
.then(function(messages){
    appLog.debug("found [%d] stored messages",messages.length);
    return Q.all(messages.map(sendAndDelete));
})
.then(function() {
    appLog.debug("all messages done");
});



回答2:


Yeah, one way to clean it up would be to defined a named function:

function SuccessfulSend(result) {
        if (result == constants.EVENT_EMIT_SENT) {
            appLog.debug("Message [%s] sent!!!", msg._id);
            messageService.remove(msg._id)
                .then(function(result) {
                     appLog.debug("Message deleted: [%s]", msg._id);
                })
                .fail(function(err) {
                    appLog.error("The message couldn't be deleted: [%s]", msg._id);
                });

        }else if (result == constants.EVENT_EMIT_NOT_SENT_AND_NOT_STORED) {
            appLog.debug("Message [%s] not sent", msg._id);
        }

    }

and then:

.then(SuccessfulSend);



回答3:


Simply refactoring your functions into named functions and trying to make better use of promise chaining would be a vast improvement.

var messageService, appLog, constants;

appLog.debug("Looking for scheduled messages");

messageService.findScheduled()
  .then(function(messages){
    appLog.debug("found [%d] stored messages", messages.length);
    messages.map(processMessage);
  });

function processMessage(msg) {

  msg.data.dontStore = true;
  messageService

    .send(msg.namespace, msg.message, msg.data)

    .then(function(result) {

      if (result !== constants.EVENT_EMIT_SENT) {
        throw new Error(constants.EVENT_EMIT_SENT);
      }

      appLog.debug("Message [%s] sent!!!", msg._id);
      return removeMessage(msg);

    })

    .fail(function(err) {
      appLog.debug("Message [%s] not sent", msg._id);
      throw err;
    });

}

function removeMessage(msg) {
  return messageService.remove(msg._id)
    .then(function() {
      appLog.message("Message deleted: [%s]", msg._id);
    })
    .fail(function(err) {
      appLog.message("The message couldn't be deleted: [%s]", msg._id);
      throw err;
    });
}


来源:https://stackoverflow.com/questions/26383057/how-to-optimize-this-node-js-q-code-to-prevent-callback-hell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!