例如,有一个只获取数据的函数
exports.content = function(req, res){
getData(req, function(err, data) {
// trivial error handling
if (err) {
console.dir('error getting your data', err);
return res.redirect('/');
}
res.render('content', data)
}
// cb is a callback function
function getData(req, cb) {
OPID = req.params.id;
titles.findOne({postID: OPID}, function (err, post) { //function #1
if (err) { return cb(err); }
readComment(OPID, function(err, comment){ //function #2 (with error handling)
if (err) { return cb(err); }
branchFilter.getBranches(function(err, branches){ //function #3
if (err) { return cb(err); }
var output = {
title: post.title,
content: post.body,
OPID: post.postID,
comments: comment, branches: branches
}
return cb(null, output);
});
});
});
}
看看http://callbackhell.com/对如何使用回调编写干净的代码提供了一个很好的概述。以下是从该站点复制的
命名你的函数
这是一些(混乱的)浏览器 javascript,它使用浏览器请求向服务器发出 AJAX 请求:
var form = document.querySelector('form')
form.onsubmit = function(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, function(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
这段代码有两个匿名函数。让我们给他们起个名字吧!
var form = document.querySelector('form')
form.onsubmit = function formSubmit(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, function postResponse(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
如您所见,命名函数非常简单,并且可以为您的代码做一些好事:
- 使代码更易于阅读
- 当发生异常时,您将获得引用实际函数名称而不是“匿名”的堆栈跟踪
- 让你的代码保持浅层,或者不深度嵌套,这让我想到了下一点:
保持你的代码浅
在最后一个示例的基础上,让我们更进一步,摆脱代码中正在进行的三层嵌套:
function formSubmit(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
document.querySelector('form').onsubmit = formSubmit
像这样的代码看起来不那么可怕,并且以后更容易编辑、重构和破解。
模块化!
这是最重要的部分:任何人都可以创建模块(AKA 库)。引用 Isaac Schlueter(node.js 项目的)的话:“编写每个做一件事的小模块,然后将它们组装成做更大事情的其他模块。如果你不去那里,你就不会陷入回调地狱。”
让我们从上面取出样板代码,然后通过将其拆分为几个文件将其转换为一个模块。由于我在浏览器和服务器上都编写了 JavaScript,因此我将展示一种在两者中都有效但仍然很好且简单的方法。
这是一个名为 formuploader.js 的新文件,其中包含我们之前的两个函数:
function formSubmit(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
exports.submit = formSubmit