Javascript 使用嵌套承诺编写干净的代码
我正在编写一个与苹果对话的应用程序来验证收据。他们有一个沙箱和一个你可以发布到的产品url 在与苹果沟通时,如果您收到21007状态,则表示您正在发布到生产url,而您应该发布到沙盒url 所以我写了一些代码来简化重试逻辑。以下是我的代码的简化版本:Javascript 使用嵌套承诺编写干净的代码,javascript,node.js,promise,Javascript,Node.js,Promise,我正在编写一个与苹果对话的应用程序来验证收据。他们有一个沙箱和一个你可以发布到的产品url 在与苹果沟通时,如果您收到21007状态,则表示您正在发布到生产url,而您应该发布到沙盒url 所以我写了一些代码来简化重试逻辑。以下是我的代码的简化版本: var request = require('request') , Q = require('q') ; var postToService = function(data, url) { var deferred = Q.defe
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;
};
verify函数中的重试部分非常难看,很难用嵌套的承诺来读取。有更好的方法吗? < P>你可以考虑如下的事情。我认为明智地使用空格有助于提高可读性。你可能会想找到一个合理的风格标准,让你的团队感觉良好,并坚持下去
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;
};
这里有几个可能性。因为这个问题有个人品味,你可能喜欢也可能不喜欢你看到的东西 (承认-我没有测试过此代码) 选项1-为
解析
和拒绝
使用包装器。这会以辅助函数的形式添加“噪波”,但会整理其余的
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的微小变化)
选项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;
};
您可以在拒绝处理程序中重新抛出错误以继续拒绝承诺,也可以返回新承诺以替换拒绝
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
}
});
};
斯图尔特的回答是对的,关键是要兑现承诺。我想澄清的是,仅仅为了包装,不需要使用Q.defer。这甚至被认为是一种反模式。看这里的原因
我想到的一个想法是使用冰镇咖啡脚本,它在语法上支持继续传递(类似于C#的async/await):。不幸的是,这需要使用CoffeeScript,以及grunt等不支持的“非标准”变体。我喜欢这样。漂亮、干净、简单!使用
Q.ninvoke
(和配偶)可以完全避免延迟
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
}
});
};
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;
}