节点承诺链:本地函数以及如何传递多个值(代码审查)

时间:2016-02-25 10:49:53

标签: javascript node.js promise bluebird control-flow

考虑到以下代码,我有以下问题:

#1 这些bluebird.all函数返回的值需要在以后的函数中访问。从我读过的内容中我也可以使用this-context,而无需在之前声明变量。但是我在嵌套函数中访问这些值时遇到了一些问题。

#2 是为了在后续功能中使这些参数可以访问的方式?

#3 由于这些函数只在main方法中工作,它们是否应该像这样嵌套?

#4 我找不到有条件的承诺链执行的更好的解决方案。如果有的话,我更喜欢一个不那么详细的解决方案。

#5 作为#3,但这次嵌套在嵌套函数中。

function create(contactRequestPayload) {

  // #1 Local variables vs this
  var
    contactRequest = {},
    property = {};

  return bluebird.all([
    new ContactRequestModel(contactRequestPayload).save(),
    getPropertyById(contactRequestPayload.propertyId),
    sendContactMail()
  ])
    // #2 Correct usage of spread
    .spread(function (_contactRequest, _property) {
      contactRequest = _contactRequest;
      property = _property;
    })
    .then(processFeedbackEmail)
    .then(updateModelState)
    .then(returnContactRequest)
    .catch(errorHandler);

  // #3 Nested functions
  function processFeedbackEmail() {
    // #4 Conditional code execution
    if (!_.get(property, "contact.email.feedback")) {
      return bluebird.resolve();
    }

    return createFeedbackObject()
      .then(convertToXml)
      .then(sendFeedbackMail)
      .catch(function (error) {
        logger.warn(error);
      });

    // #5 Nested functions within a nested function        
    function createFeedbackObject() {
      return contactRequestFeedbackObjectService.from(property, contactRequest);
    }

    function convertToXml(contactFeedbackObject) {
      contactRequest.feedbackJson = contactFeedbackObject;
      return objectToXmlService.convert(contactFeedbackObject);
    }

    function sendFeedbackMail(contactFeedbackXml) {
      contactRequest.feedbackXml = contactFeedbackXml;
      return contactRequestFeedbackMailService.send(property.contact.email.feedback, contactFeedbackXml);
    }
  }

  function returnContactRequest() {
    return contactRequest;
  }

  function sendContactMail() {
    return searchServiceClient.sendContactMail(contactRequestPayload);
  }

  function getPropertyById(propertyId) {
    return getPropertyServiceClient().fetchPropertyById(propertyId);
  }

  function updateModelState() {
    contactRequest.state = 'SENT';
    return contactRequest.save();
  }
}

1 个答案:

答案 0 :(得分:2)

Promise-chains让我们按照同步代码的顺序对事物进行排序。我发现内联函数重新获得了重要的背景。要使用以前的变量,我使用旧的缩进:

function create(contactRequestPayload) {
  return bluebird.all([
    new ContactRequestModel(contactRequestPayload).save(),
    getPropertyServiceClient().fetchPropertyById(contactRequestPayload.propertyId),
    searchServiceClient.sendContactMail(contactRequestPayload)
  ])
  .spread(function processFeedbackEmail(contactRequest, property) {
    if (_.get(property, "contact.email.feedback")) {
      return contactRequestFeedbackObjectService.from(property, contactRequest)
      .then(function convertToXml(feedback) {
        contactRequest.feedbackJson = feedback;
        return objectToXmlService.convert(feedback);
      })
      .then(function sendFeedbackMail(xml) {
        contactRequest.feedbackXml = xml;
        return CRFeedbackMailService.send(property.contact.email.feedback, xml);
      })
      .catch(function (error) {
        logger.warn(error);
      });
    }
  })
  .then(function updateModelState() {
    contactRequest.state = 'SENT';
    return contactRequest.save();
  })
  .then(function returnContactRequest() {
    return contactRequest;
  })
  .catch(errorHandler);
}

(函数名称当然是可选的,但我保留了它们以供参考。)

对于条件,我将其反转,因为返回undefined等于bluebird.resolve()

有些人可能认为这是一个风格问题,但ES7将这个类比归结为其自然结论:

async function create(contactRequestPayload) {
  var [ contactRequest, property ] = await Promise.all([
    new ContactRequestModel(contactRequestPayload).save(),
    getPropertyServiceClient().fetchPropertyById(contactRequestPayload.propertyId),
    searchServiceClient.sendContactMail(contactRequestPayload)
  ]);
  if (_.get(property, "contact.email.feedback")) {
    try {
      var feedback = await contactRequestFeedbackObjectService.from(property,
                                                                    contactRequest);
      contactRequest.feedbackJson = feedback;
      contactRequest.feedbackXml = await objectToXmlService.convert(feedback);
      await CRFeedbackMailService.send(property.contact.email.feedback, xml);
    } catch (error) {
      logger.warn(error);
    }
  }
  contactRequest.state = 'SENT';
  await contactRequest.save();
  return contactRequest;
}