5

我正在编写一个与 Apple 对话以验证收据的应用程序。他们有一个沙盒和生产 URL,您可以发布到它们。

与 Apple 通信时,如果您收到 21007 状态,则表示您正在发布到生产 url,而您应该发布到沙盒一。

所以我写了一些代码来方便重试逻辑。这是我的代码的简化版本:

var request = require('request')
  , Q = require('q')
  ;

var postToService = function(data, url) {
  var deferred = Q.defer();
  var options = {
    data: data,
    url: url
  };

  request.post(options, function(err, response, body) {
    if (err) { 
      deferred.reject(err);
    } else if (hasErrors(response)) {
      deferred.reject(response);
    } else {
      deferred.resolve(body);
    }
  });

  return deferred.promise;
};

exports.verify = function(data) {
  var deferred = Q.defer();

  postToService(data, "https://production-url.com")
    .then(function(body) {
      deferred.resolve(body);
    })
    .fail(function(err) {
      if (err.code === 21007) {
        postToService(data, "https://sandbox-url.com")
          .then(function(body){
            deferred.resolve(body);
          })
          .fail(function(err) {
            deferred.reject(err);
          });
      } else {
        deferred.reject(err);
      }

    });

  return deferred.promise;
};

验证函数中的重试部分非常难看,嵌套的 Promise 很难阅读。有没有更好的方法来做到这一点?

4

4 回答 4

5

您可以在拒绝处理程序中重新抛出错误以继续拒绝承诺,或者您可以返回新的承诺以替换拒绝。

exports.verify = function(data) {
  return postToService(data, "https://production-url.com")
    .fail(function(err) {
      if (err.code === 21007) {
        return postToService(data, "https://sandbox-url.com")
      } else {
        throw err
      }
    });
};
于 2013-04-10T00:05:43.643 回答
1

这里有几种可能性。因为这个问题有个人品味的元素,你可能喜欢也可能不喜欢你看到的!

入场 - 我没有测试过这个代码

resolve选项 1 - 为和使用包装器reject。这会以辅助函数的形式添加“噪音”,但会整理其余部分。

var resolve = function (deferred, ob) {
  return function () {
    deferred.resolve(ob);
  };
};

var reject = function (deferred, ob) {
  return function () {
    deferred.reject(ob);
  };
};

exports.verify = function(data) {
  var deferred = Q.defer();

  postToService(data, "https://production-url.com")
    .then(resolve(deferred, body))
    .fail(function(err) {
      if (err.code === 21007) {
        postToService(data, "https://sandbox-url.com")
          .then(resolve(deferred, body))
          .fail(reject(deferred, err));
      } else {
        deferred.reject(err);
      }
    });

  return deferred.promise;
};

选项 2 - 使用绑定。这具有使用现有 JS 功能的优势,但是deferred在创建回调时您有重复的引用。

exports.verify = function(data) {
  var deferred = Q.defer();

  postToService(data, "https://production-url.com")
    .then(deferred.resolve.bind(deferred, body))
    .fail(function(err) {
      if (err.code === 21007) {
        postToService(data, "https://sandbox-url.com")
          .then(deferred.resolve.bind(deferred, body))
          .fail(deferred.reject.bind(deferred, err));
      } else {
        deferred.reject(err);
      }
    });

  return deferred.promise;
};

选项 3 - 使用绑定和“方法句柄”(#2 的细微变化)。

exports.verify = function(data) {
  var deferred = Q.defer();
  var resolve = deferred.resolve;
  var reject = deferred.reject;

  postToService(data, "https://production-url.com")
    .then(resolve.bind(deferred, body))
    .fail(function(err) {
      if (err.code === 21007) {
        postToService(data, "https://sandbox-url.com")
          .then(resolve.bind(deferred, body))
          .fail(reject.bind(deferred, err));
      } else {
        deferred.reject(err);
      }
    });

  return deferred.promise;
};

选项 4 - Monkey 补丁延迟。

function patch(deferred) {
  deferred.resolveFn = function (ob) {
    return function () {
      deferred.resolve(ob);
    };
  };
  deferred.rejectFn = function (ob) {
    return function () {
      deferred.reject(ob);
    };
  };
  return deferred;
}

exports.verify = function(data) {
  var deferred = patch(Q.defer());

  postToService(data, "https://production-url.com")
    .then(deferred.resolveFn(body))
    .fail(function(err) {
      if (err.code === 21007) {
        postToService(data, "https://sandbox-url.com")
          .then(deferred.resolveFn(body))
          .fail(deferred.rejectFn(err));
      } else {
        deferred.reject(err);
      }
    });

  return deferred.promise;
};
于 2013-04-09T22:33:27.210 回答
0

您可能会考虑以下内容。我认为明智地使用空格有助于提高可读性。您可能希望找到一个合理的风格标准,让您的团队感觉良好并坚持下去!

exports.verify = function(data) {
  var deferred = Q.defer();

  postToService(data, "https://production-url.com")

    .then(deferred.resolve, function(err) {

      if (err.code === 21007) {

        postToService(data, "https://sandbox-url.com")

          .then(deferred.resolve, deferred.reject);

      } else { deferred.reject(err); }

    });

 return deferred.promise;
};
于 2013-04-09T22:33:20.097 回答
0

斯图尔特的回答是对的,关键是要连锁承诺。我想澄清一下,不需要使用 Q.defer 来包装。它甚至被认为是一种反模式。在此处查看原因延迟的反模式

var request = require('request')
    , Q = require('q');

var PRODUCTION_URL = "https://production-url.com",
var SANDBOX_URL    = "https://sandbox-url.com",


export.verify = function() {

  return postToProduction(data)
         .fail( function(error) {
             if (error.code === 21007 ) return postToSanbox(data);
             throw error;
         });
}

function postToProduction(data) {
    return postToService(data, PRODUCTION_URL);
}

function postToSandbox(data) {
    return postToService(data, SANDBOX_URL);
}

function postToService(data, url) {
   var deferred = Q.defer();

   var options = {
      data: data,
      url: url
   };

  request.post(options, function(err, response, body) {
    if (err) return deferred.reject(err);
    if (hasErrors(response)) return deferred.reject(response);

    deferred.resolve(body);    
  });

  return deferred.promise;   
}
于 2015-04-07T17:12:02.250 回答