了解Layman术语中的异步代码

时间:2021-12-02 19:30:32

I understand the basic thing about asynchronous-ness: things don't execute sequentially. And I understand there is something very powerful about that... allegedly. But for the life of me I can't wrap my head around the code. Let's take a look at async Node.JS code that I HAVE WRITTEN...but don't truly get.

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

Where did response come from again? postData? Why can't I define a variable in this "callback" and then use it outside of the callback? Is there a way to have a few things be sequential then the rest of the program async?

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

3 个解决方案

#1


43  

I'm not sure where this function is being used, but the point of callbacks is that you pass them into some function that runs asynchronously; it stores your callback away, and when that function is done with whatever it needs to do, it will call your callback with the necessary parameters. An example from front-to-back is probably best.

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

Imagine we have a framework, and in it there is an operation that runs for a long time, fetching some data from the database.

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

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

Since we don't want it to run synchronously, we'll allow the user to pass in a callback.

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

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

We'll simulate taking a long time with a call to setTimeout; we'll also pretend we got some data from the database, but we'll just hardcode a string value.

我们将模拟调用setTimeout需要很长时间;我们还假装从数据库中获取了一些数据,但我们只是对字符串值进行硬编码。

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

Finally, once we have the data, we'll call the callback given to us by the user of the framework's function.

最后,一旦我们获得了数据,我们将调用框架函数的用户给我们的回调。

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

As a user of the framework, you'd do something like this to use the function:

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

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

So, as you can see data (same as response and postData in your example) came from the function that you pass your callback into; it gives that data to you when it knows what that data should be.

因此,您可以看到数据(与示例中的response和postData相同)来自您将回调传递给的函数;当它知道该数据应该是什么时,它会将数据提供给您。

The reason you can't set a value in your callback and use it outside the callback is because the callback itself doesn't happen until later in time.

你无法在回调中设置值并在回调之外使用它的原因是因为回调本身直到晚些时候才会发生。

//  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

When the console.log runs, the assignment of var results hasn't happened yet!

当console.log运行时,var结果的分配还没有发生!

#2


7  

You have several unrelated questions here:

你有几个不相关的问题:

1) The power of async is being able to do multiple things at the same time without locking the main thread. In node and js in general, this applies particularly to ajax file requests. This means that I can fire off several async calls to retreive files, and not lock the main thread while it renders the content. My preferred framework is jQuery, which has convenient $.Deferred that wraps and standardizes async calls for jQuery usage.

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

2) response and postData come from the parent method. There's nothing magical here, it's a normal function call, so the values of these are created elsewhere and passed into this invocation. Depending on which node framework you have, the exact signature of your method will change.

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

3) You can define a global variable in your callback if it's properly scoped. It seem though that you need help learning what scope is. Here are some links

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

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

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

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

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

4) Once you go async, you can never go back, however, by leveraging promise and deferred objects like with jQuery Deferreds you can wait for several asyncs to complete before continuing your execution in yet another async. Deferreds are your friends.

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

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

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

#3


2  

Looks like you're working through the Node Beginner Book. I encourage you to work through the entire book, it really is an excellent introduction. If you are trying to understand Javascript better, Douglas Crockford's videos on YouTube are a great overview: 1, 2.

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

The piece of code you've posted doesn't have enough context for me to really help you. response is a parameter that you're passing to your function, it does not come from postData. If you are working with code the way the Node Beginner Book suggests, you are probably passing response to your newuser function all the way down from the createServer function, which is part of the http module that comes with Node.

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

You can't define a variable in the callback and then use it in the callback because Javascript is lexically scoped. Here's a Stack Overflow post on the topic of Javascript's scope. The first video by Doug Crockford that I posted also has a great explanation of Javascript's scoping rules.

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

Javascript isn't necessarily async. It simply provides anonymous functions that are closures, which are a useful tool for easily implementing async logic. Again, the Node Beginner Book shows a good example of writing synchronous code with Node (not what you want), then rewriting it to make it async.

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

#1


43  

I'm not sure where this function is being used, but the point of callbacks is that you pass them into some function that runs asynchronously; it stores your callback away, and when that function is done with whatever it needs to do, it will call your callback with the necessary parameters. An example from front-to-back is probably best.

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

Imagine we have a framework, and in it there is an operation that runs for a long time, fetching some data from the database.

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

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

Since we don't want it to run synchronously, we'll allow the user to pass in a callback.

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

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

We'll simulate taking a long time with a call to setTimeout; we'll also pretend we got some data from the database, but we'll just hardcode a string value.

我们将模拟调用setTimeout需要很长时间;我们还假装从数据库中获取了一些数据,但我们只是对字符串值进行硬编码。

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

Finally, once we have the data, we'll call the callback given to us by the user of the framework's function.

最后,一旦我们获得了数据,我们将调用框架函数的用户给我们的回调。

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

As a user of the framework, you'd do something like this to use the function:

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

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

So, as you can see data (same as response and postData in your example) came from the function that you pass your callback into; it gives that data to you when it knows what that data should be.

因此,您可以看到数据(与示例中的response和postData相同)来自您将回调传递给的函数;当它知道该数据应该是什么时,它会将数据提供给您。

The reason you can't set a value in your callback and use it outside the callback is because the callback itself doesn't happen until later in time.

你无法在回调中设置值并在回调之外使用它的原因是因为回调本身直到晚些时候才会发生。

//  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

When the console.log runs, the assignment of var results hasn't happened yet!

当console.log运行时,var结果的分配还没有发生!

#2


7  

You have several unrelated questions here:

你有几个不相关的问题:

1) The power of async is being able to do multiple things at the same time without locking the main thread. In node and js in general, this applies particularly to ajax file requests. This means that I can fire off several async calls to retreive files, and not lock the main thread while it renders the content. My preferred framework is jQuery, which has convenient $.Deferred that wraps and standardizes async calls for jQuery usage.

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

2) response and postData come from the parent method. There's nothing magical here, it's a normal function call, so the values of these are created elsewhere and passed into this invocation. Depending on which node framework you have, the exact signature of your method will change.

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

3) You can define a global variable in your callback if it's properly scoped. It seem though that you need help learning what scope is. Here are some links

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

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

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

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

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

4) Once you go async, you can never go back, however, by leveraging promise and deferred objects like with jQuery Deferreds you can wait for several asyncs to complete before continuing your execution in yet another async. Deferreds are your friends.

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

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

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

#3


2  

Looks like you're working through the Node Beginner Book. I encourage you to work through the entire book, it really is an excellent introduction. If you are trying to understand Javascript better, Douglas Crockford's videos on YouTube are a great overview: 1, 2.

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

The piece of code you've posted doesn't have enough context for me to really help you. response is a parameter that you're passing to your function, it does not come from postData. If you are working with code the way the Node Beginner Book suggests, you are probably passing response to your newuser function all the way down from the createServer function, which is part of the http module that comes with Node.

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

You can't define a variable in the callback and then use it in the callback because Javascript is lexically scoped. Here's a Stack Overflow post on the topic of Javascript's scope. The first video by Doug Crockford that I posted also has a great explanation of Javascript's scoping rules.

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

Javascript isn't necessarily async. It simply provides anonymous functions that are closures, which are a useful tool for easily implementing async logic. Again, the Node Beginner Book shows a good example of writing synchronous code with Node (not what you want), then rewriting it to make it async.

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