繁体   English   中英

节点中的回调混淆和数据收集

[英]Callback Confusion and Collecting Data in Node

我是Node的新手,在跟踪这里发生的事情时遇到了麻烦。 我的评论在下面,但基本上我真的很难理解为什么utils.collectData中的回调在那里(第二个参数)以及它如何任意添加到messages数组中。 我怎么知道将来自然要这样做? 我知道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));
            })
        }

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

回调几乎总是采用两个参数: errdata (或errresult ,或errwhateverYouAreLookingFor )。 如果函数中发生错误,则该错误将返回到您的回调中,并且如果该函数的执行产生了任何数据,则该错误也将返回到您的回调中。

这种模式的优点在于,您永远不会被迫阻塞事件循环:无论任务的复杂性如何,脚本都将保持愉快的响应。 当老板在星期五的午餐后将构思不佳的项目放到办公桌上,然后提早打工去打高尔夫球时,您实际上是在扮演异步功能。

这里的挑战是,在调用回调时,它是原始请求的唯一存活链接。 其含义是双重的:

  1. 任何用于处理响应的逻辑都必须包含在回调中或回调可以访问;

  2. 对于处理异步函数抛出的任何错误,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.readFilefs.readFileSync 不要屈服于使用它们; 一旦习惯了异步,它就非常简单,而且刚开始时,您需要获得所有可能的实践。

祝你好运。

NodeJ的主要功能之一就是并发性(以一种简单的方式)。 开始在NodeJ中进行编程的最好方法是认为所有与外部资源交互的代码都必须遵循以下一种模式:

  • 回呼
  • 无极(ES2015)
  • 异步/等待(ES2016)

为什么是这样?

当您以异步方式调用外部资源(HTTP服务,文件等)时。 主进程创建一个内部线程并执行代码,这样做是为了不阻塞主进程。

回调:

这是在javascript中管理并发的第一种方法,因为函数是一流的,所以您只传递要执行的函数,而主函数则在调用时进行选择。

在您的示例中,您正在使用这种方法。 您正在从请求中读取数据并存储在本地变量中,当请求启动事件“ end”时,您选择使用数据作为参数调用回调,而“ POST”使用该数据来操纵消息并发送响应。

将来存在另外两个选项,今天都可以使用,但是Async / Await处于tc39的第2阶段http://tc39.github.io/ecmascript-asyncawait/

诺言:

这是当今最流行的方式,您可以将本机与NodeJ的版本4一起使用,也可以使用QBlueBird之类的库。 这项工作有点不同,我建议阅读有关promise的邮寄文章 ,这里我将展示使用promise编写的代码:

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

甚至当我从Java开始使用NodeJS编程时,因为这是设计程序从阻塞IO到非阻塞IO的重大转变,我也面对着上面的代码的理解。

在非阻塞IO中,一切都基于事件和回调进行。 在上面的代码中,调用collectData时,nodejs(eventloop)将等待on(带有回调以收集数据)和on(带有您提供的用于处理完成的请求的回调)事件。

在NodeJS中很简单,任何阻塞代码(网络调用或对任何IO设备的访问)都将标记一个事件,该事件将在I / O操作完成后触发。 希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM