如何优化这个Node.js + q代码以防止回调地狱?

时间:2014-10-15 12:48:51

标签: node.js callback promise q

我正在使用 Q 来阻止回调地狱,但我已经达到了我不知道如何安排的部分代码:

我正在搜索要传递的预定消息。对于它们中的每一个,我尝试逐个发送它们,如果它可以被发送,则将其从数据库中删除。丑陋的部分是在for循环中有一个 then()。这样我最终得到嵌套的promises而不是嵌套的回调!!!!建议?

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

        });
    }
});

3 个答案:

答案 0 :(得分:1)

  

丑陋的部分是在for循环中有一个then()

不,那可能发生。虽然promises的函数式编程风格通常会导致.map()使用回调:-)循环是一个控制结构,并且需要嵌套(除了use exceptions for control flow,即ie分枝)。但是,您不必做的是在承诺回调中嵌套承诺。

我将你的循环体简化为

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

现在你可以做类似

的事情了
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");
});

答案 1 :(得分:0)

是的,清理它的一种方法是定义一个命名函数:

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

    }

然后:

.then(SuccessfulSend);

答案 2 :(得分:0)

简单地将您的函数重构为命名函数,并尝试更好地使用promise链接将是一个巨大的改进。

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