21

我了解异步性的基本知识:事情不会按顺序执行。我知道这有一些非常强大的东西……据说。但是对于我的生活,我无法将我的头包裹在代码上。让我们看一下我已经编写的异步 Node.JS 代码......但并没有真正得到。

function newuser(response, postData) {
    console.log("Request handler 'newuser' was called.");
    var body = '<html>' + 
        '<head>' +
        '<meta http-equiv="Content-Type" content="text/html; ' +
        'charset=UTF-8" />' +
        '</head>' +
        '<body>' +
        '<form action=" /thanks" method="post">' +
        '<h1> First Name </h1>' +
        '<textarea name="text" rows="1" cols="20"></textarea>' +
        '<h1> Last Name </h1>' +
        '<textarea name="text" rows="1" cols="20"></textarea>' +
        '<h1> Email </h1>' +
        '<textarea name="text" rows="1" cols="20"></textarea>' +
        '<input type="submit" value="Submit text" />' +
        '</body>' +
        '</html>';
    response.writeHead(200, { "Content-Type": "text/html" });
    response.write(body);
    response.end();
}

又是从哪里来的回应?发布数据?为什么我不能在这个“回调”中定义一个变量,然后在回调之外使用它?有没有办法让一些事情是顺序的,然后程序的其余部分是异步的?

4

3 回答 3

45

我不确定这个函数在哪里使用,但回调的重点是你将它们传递给一些异步运行的函数;它将你的回调存储起来,当该函数完成它需要做的任何事情时,它会使用必要的参数调用你的回调。从前到后的例子可能是最好的。

想象一下,我们有一个框架,其中有一个运行很长时间的操作,从数据库中获取一些数据。

function getStuffFromDatabase() {
  // this takes a long time
};

由于我们不希望它同步运行,我们将允许用户传入回调。

function getStuffFromDatabase(callback) {
  // this takes a long time
};

我们将通过调用来模拟花费很长时间setTimeout;我们也会假装我们从数据库中得到了一些数据,但我们只是硬编码一个字符串值。

function getStuffFromDatabase(callback) {
  setTimeout(function() {
    var results = "database data";
  }, 5000);
};

最后,一旦我们有了数据,我们就会调用框架函数的用户给我们的回调。

function getStuffFromDatabase(callback) {
  setTimeout(function() {
    var results = "database data";
    callback(results);
  }, 5000);
};

作为框架的用户,您可以执行以下操作来使用该功能:

getStuffFromDatabase(function(data) {
  console.log("The database data is " + data);
});

因此,正如您所看到data的(与您的示例相同responsepostData来自您将回调传递给的函数;当它知道该数据应该是什么时,它会将该数据提供给您。

您无法在回调中设置值并在回调之外使用它的原因是回调本身直到稍后才会发生。

//  executed immediately  executed sometime in the future
//      |                  |       by getStuffFromDatabase
//      v                  v
getStuffFromDatabase(function(data) {
  var results = data; // <- this isn't available until sometime in the future!
});

console.log(results); // <- executed immediately

运行时console.log,任务var results尚未发生!

于 2012-06-27T19:48:03.380 回答
8

您在这里有几个不相关的问题:

1) async 的强大之处在于能够在不锁定主线程的情况下同时执行多项操作。在一般的 node 和 js 中,这尤其适用于 ajax 文件请求。这意味着我可以触发多个异步调用来检索文件,并且在呈现内容时不会锁定主线程。我首选的框架是 jQuery,它有方便的 $.Deferred 包装和标准化 jQuery 使用的异步调用。

2) response 和 postData 来自父方法。这里没有什么神奇的,它是一个普通的函数调用,所以这些值在别处创建并传递给这个调用。根据您拥有的节点框架,您的方法的确切签名将发生变化。

3)如果范围正确,您可以在回调中定义一个全局变量。尽管您似乎需要帮助来了解范围是什么。这里有一些链接

http://www.digital-web.com/articles/scope_in_javascript/

http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/

4) 一旦你进入异步,你就永远无法返回,然而,通过利用承诺和延迟对象,如 jQuery Deferreds,你可以等待几个异步完成,然后再继续执行另一个异步。延期者是你的朋友。

http://api.jquery.com/category/deferred-object/

于 2012-06-27T19:51:59.290 回答
2

看起来您正在阅读Node Beginner Book。我鼓励你通读整本书,这确实是一个很好的介绍。如果您想更好地理解 Javascript,Douglas Crockford 在 YouTube 上的视频是一个很好的概述1、2

您发布的那段代码没有足够的上下文让我真正帮助您。response是您传递给函数的参数,它不是来自 postData。如果您按照 Node Beginner Book 建议的方式使用代码,您可能会将响应从 createServer 函数一直向下传递给 newuser 函数,该函数是 Node 附带的 http 模块的一部分。

您不能在回调中定义变量然后在回调中使用它,因为 Javascript 是词法范围的。这是关于 Javascript 范围主题的Stack Overflow 帖子。我发布的 Doug Crockford 的第一个视频也很好地解释了 Javascript 的范围规则。

Javascript 不一定是异步的。它只是提供匿名函数,它们是闭包,这是一个用于轻松实现异步逻辑的有用工具。同样,Node Beginner Book 展示了使用 Node 编写同步代码(不是您想要的),然后重写它以使其异步的一个很好的示例。

于 2012-06-27T19:57:54.560 回答