了解Layman术语中的异步代码

时间:2012-06-27 19:32:04

标签: javascript node.js asynchronous

我理解异步的基本内容:事情不按顺序执行。据我所知,有一些非常强大的东西......但对于我的生活,我无法绕过代码。让我们来看看我写过的异步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();
}

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

3 个答案:

答案 0 :(得分:43)

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

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

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的分配尚未发生!

答案 1 :(得分:8)

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

1)async的强大功能是能够在不锁定主线程的情况下同时执行多项操作。在节点和js中,这通常适用于ajax文件请求。这意味着我可以触发几个对retreive文件的异步调用,而不是在呈现内容时锁定主线程。我首选的框架是jQuery,它有方便的$ .Deferred,包装和标准化jQuery使用的异步调用。

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

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

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

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

4)一旦你去异步,你永远不会回头,但是,通过利用promise和延迟对象,比如jQuery Deferreds,你可以等待几个asyncs完成,然后再继续执行另一个异步。延期是你的朋友。

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

答案 2 :(得分:2)

看起来你正在使用Node Beginner Book。我鼓励你完成整本书,这真是一个很好的介绍。如果你想更好地理解Javascript,道格拉斯·克罗克福德在YouTube上的视频是一个很好的概述:12

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

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

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