用嵌套的承诺编写干净的代码

我正在写一个应用程序,与苹果进行validation以validation接收。 他们有一个沙箱和生产url,你可以张贴到。

在与苹果进行通信时,如果您收到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; }; 

validation函数中的重试部分相当丑陋,难以用嵌套的promise读取。 有没有更好的方法来做到这一点?

您可以在拒绝处理程序中重新抛出错误,继续拒绝承诺,也可以返回新的承诺来replace拒绝。

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

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

入场 – 我没有testing过这个代码

选项1 – 使用包装来resolvereject 。 这会以助手function的forms增加“噪音”,但是整理其余部分。

 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 – 使用绑定。 这具有使用现有的JSfunction的优点,但是在创buildcallback时,您有重复的引用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 – 猴子补丁延期。

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

你可能会考虑如下的东西。 我认为明智地使用空格可以提高可读性。 你可能会想find一个合理的风格标准,你的团队感觉很好,坚持下去!

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

斯图亚特的答案是正确的,重点是联系承诺。 我想澄清一下,不需要使用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; }