我是节点新手,无法跟踪此处发生的事情。我的评论如下,但基本上我真的很难理解为什么utils.collectData中的回调存在(第二个参数)以及它如何随意添加 消息数组。我怎么知道将来自然会做到这一点?我知道collectData函数被定义为将回调作为其第二个参数,所以让我们从那里开始......
var utils = require('./utils');
"POST": function(request, response) {
//collect the data
utils.collectData(request, function(message) {
message.objectID = ++objectIDcounter;
messages.push(message);
utils.sendResponse(response, {
objectID: message.objectID
}, 201)
})
}
// this is in utils.js:
//why is a callback parameter passed to this function?
exports.collectData = function(request, callback) {
var data = ""
request.on('data', function(chunk) {
data += chunk;
})
request.on('end', function() {
//why is the callback applied here?
//Also, we are parsing the data here. why? because it is a buffer or a string here?
callback(JSON.parse(data));
})
}
答案 0 :(得分:2)
Node.js中的异步操作遵循简单一致的模式。掌握这一点将使您的体验更加愉快,您的应用程序更快,更稳定。
我认为这里的其他答案都缺少了一点。您调用的方法遵循Node.js生态系统中普遍存在的异步模式。有许多模式可以简化这一点,但您的首要任务应该是彻底了解正在发生的事情以及它对您的代码产生的影响。这很简单:
asyncFunction(functionArguments, callback);
当您调用任何异步函数时,当该函数的结果处于挂起状态时,您的脚本将继续执行。由于您无法保证结果何时准备好,因此在继续操作之前,您需要为结果提供功能。通常,您提供的回调将是匿名函数,例如:
getExternalData('http://example.com', function(err, data) {
console.log('I got the data!');
// presumably do something with the data
});
回调几乎总是会有两个参数:err
和data
(或err
和result
,或err
和whateverYouAreLookingFor
) 。如果函数中发生错误,它将返回到您的回调,如果任何数据来自函数的执行,它也将返回到您的回调。
这种模式的优点在于,您永远不会被迫阻止事件循环:无论任务的复杂程度如何,您的脚本都会保持愉快的响应。当你的老板在星期五的午餐后将一个设计不良的项目放到你的桌面上,然后提前离开高尔夫球场时,你实际上是一个异步的角色扮演角色。
这里的挑战是,当您的回调被调用时,它是原始请求的唯一幸存链接。这涉及到两个方面:
处理响应的任何逻辑必须包含在回调中或者可以被回调访问;以及
try / catch块对于处理异步函数抛出的任何错误完全没用。
第一个含义是通常被描述为“回调地狱”的起源:回调中回调内的深度嵌套回调。您可以通过提前计划,保持函数较小以及遵循相同的参数约定来轻松避免这种情况。
第二个含义意味着您的回调必须检查错误。您通常不会看到抛出的错误,因为在此模式下安全处理抛出的错误的唯一方法是将几乎所有代码放在try / catch块中。相反,错误将作为第一个参数传递给回调。如果没有生成错误,则第一个参数将为null。
const myCallback = function(err, data) {
if (!!err) {
console.log('Well, that was a failure');
return err;
}
console.log('Everything's great!');
}
这最终有点冗长,但是你对这种模式感到满意是至关重要的。一些核心模块具有正常和同步版本的功能,例如fs.readFile
和fs.readFileSync
。不要屈服于使用它们;一旦你习惯了异步,异步就非常简单了,刚开始时,你需要所有的练习。
祝你好运。
答案 1 :(得分:0)
NodeJs的一个主要特征是同时发生(以一种简单的方式)。在NodeJ中开始编程的最好方法是认为与外部资源交互的所有代码都必须遵循以下模式之一:
为什么会这样?
以异步方式调用外部资源(HTTP服务,文件等)。主进程创建一个内部线程并执行代码,这样做不会阻止主进程。
回调:
是第一种在javascript中管理并发的方法,因为函数是一流的,你只传递你想要执行的函数,主函数在调用它时选择。
在您的示例中,您正在使用此方法。您正在从请求中读取数据并存储在本地变量中,当请求启动事件'end'时,您选择以数据作为参数调用回调,并且“POST”使用该数据来操作消息并发送响应
将来会有另外两个选项,两个都可以在今天使用,但Async / Await在tc39 http://tc39.github.io/ecmascript-asyncawait/的第2阶段。
无极:
今天是最受欢迎的方式,您可以使用NodeJ版本4的原生版本,也可以使用Q或BlueBird等库。这项工作有点不同,我建议阅读有关承诺的pouchd post,这里我将展示使用promises编写的代码:
var utils = require('./utils');
"POST": function(request, response) {
//collect the data
utils.collectData(request)
.then(function(message) {
message.objectID = ++objectIDcounter;
messages.push(message);
return utils.sendResponse(response, {
objectID: message.objectID
}, 201);
}))
.catch(function(err) {
//Some error happend with the reques
});
}
// this is in utils.js:
//why is a callback parameter passed to this function?
exports.collectData = function(request) {
return new Promise(function (resolve, reject) {
var data = ""
request.on('data', function(chunk) {
data += chunk;
});
request.on('end', function() {
resolve(JSON.parse(data));
});
request.on('error', function(err) {
reject(err);
});
}
}
答案 2 :(得分:0)
即使我开始使用Java编程NodeJS,因为我们的程序设计从阻塞IO到非阻塞IO也发生了重大转变,我也很容易理解上面的代码。
这里的非阻塞IO一切都基于事件&回调。在上面调用collectData的代码中,nodejs(eventloop)将等待(使用回调来收集数据)& on(使用您提供的回调来处理已完成的请求)事件。
在NodeJS中很简单,任何阻塞代码(网络调用或对任何IO设备的访问)都将被标记一个事件,该事件将在I / O操作完成后触发。希望这会有所帮助。