【问题标题】:Node.js Asynchronous Function *Definition*Node.js 异步函数 *定义*
【发布时间】:2012-10-11 09:00:46
【问题描述】:

拜托,只是为了清除我脑海中的一些东西......

我习惯于在库中使用异步函数编写,但我如何编写自己的函数?

为了说明我的问题,我编写了一个名为“MadMathz”的模块

我知道以下是异步函数的示例用法:

//load module
var mM = require('./MadMathz');

//perform a function
mM.async_function_addthree(12, function(result) {
  console.log(result)
});

//do something straight afterwards
console.log('Logging this straight after instead of waiting for computation');

我知道函数的第二个参数是回调,但如何定义诸如“async_function_addthree”之类的函数?假设出于本示例的目的,async_function_addthree 只是将 3 添加到第一个参数。

我只是让自己很困惑,试图写出我认为可能的内容。我完全走错了吗?我觉得我已经接近使用 node.js 了,但这需要清理一下。

如果可能,请解释而不是在某个地方链接我。我相信其他人会从这个问题中受益。

【问题讨论】:

    标签: javascript node.js asynchronous


    【解决方案1】:

    实际上,在没有任何进一步描述或要求的情况下创建“异步”函数听起来有点奇怪。通常,使用是为了避免长时间的阻塞。因此,如果我们有一个触发数据库查询的函数,并且我们想在完成后调用另一个函数,则该函数应该在工作完成后调用,并且原始函数会立即返回控制权-流回 Node (ECMAscript)。

    所以如果我们有一个类似的构造

    function someJob( callback ) {
        // heavy work
        callback();
    }
    

    现在,这段代码仍然非常同步运行。要将其置于 async 状态,我们可以调用节点的 process.nextTick 方法

    function someJob( callback ) {
        // heavy work
        process.nextTick( callback );
    }
    

    现在发生的事情是,Node 将在稍后通过其事件循环运行时执行该 callback 方法(它也这样做有点智能)。 Eventho nextTick 声称比 setTimeout 更有效率,这几乎是相同的交易(从 ECMAscript 编码人员的角度来看)。所以在浏览器中我们可以像

    function someJob( callback ) {
        // heavy work
        setTimeout( callback, 0 );
    }
    

    如果说上面的示例方法根本没有多大意义,那你是对的,因为 async 状态发生在 繁重的工作之后。嗯,没错。事实上,您需要将繁重的部分分解为更小的部分,并使用.nextTick() 使用相同的想法,以使其真正高效。

    这也是我一开始困惑的原因,其实每个任务都已经为你提供了回调的可能性。

    【讨论】:

    • 您忘记更新浏览器的代码以使用 setTimeout 我猜 ;) 好答案!
    • 多么好的答案。这让我明白了很多。我将等到我完成工作后将其标记为正确,以便让其他人有机会回答一个相当“开放式”的问题。但到目前为止,你赢了。谢谢。
    【解决方案2】:

    这不是 node.js 模块代码,但我希望你明白。

    函数是 JavaScript 中的第一类对象。这就是为什么您可以将它们分配给变量并将它们像任何值一样传递给其他函数。一旦你有一个函数的引用,你只需在函数引用后面加上() 来调用它。

    例子:

    function async_function_addthree(a, callback) {
        callback(a + 3);
    }
    

    这会将3 添加到第一个参数,然后调用第二个参数将结果传递给它。请记住,您可以随意命名参数。重要的是第二个参数将包含一个您可以调用的函数。

    但请注意:接受回调的函数不会自动异步。在这个例子中,代码仍然按照定义的顺序执行,即首先是async_function_addthree,然后是回调,然后是调用async_function_addthree之后的所有内容,例如console.log

    您可以添加setTimeout 并延迟调用回调:

    function async_function_addthree(a, callback) {
        setTimeout(function() {
            callback(a + 3);
        }, 1000);
    }
    

    这将在一秒钟后调用回调。 Node.js 甚至内置了更好的方法,请参阅jAndy's answer

    但即使您的代码不是异步的,使用回调也是一个明智的设计选择,因为它允许您轻松更改函数的行为并在以后使其异步而不破坏现有代码。

    【讨论】:

    • 非常感谢,这是一个很好的答案。 +1
    【解决方案3】:

    当您将一些工作委派给 外部 进程(或者可能是 Node 的 C 层中的一些工作)时,NodeJS 进程中的异步就会发生,例如数据库查询、文件系统操作。

    在普通的 JavaScript 函数中通常没有异步性(Node.js 是单线程的),这样的有效案例并不多。但是,如果它真的很重,并且您真的想这样做,您可以将您的工作委托给其他进程(参见 child_process.fork)或在 setTimeout 的帮助下拆分操作(让进程喘息以处理其他请求),然后确实应该配置成异步函数。

    【讨论】:

      【解决方案4】:

      我在自己寻找答案时遇到了这个问题。

      基本上,要在节点中编写一个异步函数,你给它的参数之一应该是一个函数;您稍后将在异步函数中调用该函数。

      然后,当人们调用您的函数时,他们将能够定义该函数。

      这是我以同步方式编写但不起作用的代码示例,以及我如何将其重写为异步并实际工作。


      以下代码不起作用:

      //synchronous function that doesn't work
      var google_request  = function(animal_name, sessionid){
          var options = {
              url: 'http://google.com',
              method: 'POST',
              json: {
                  "animal": animal_name,
                  "sessionid": sessionid
              }
          };
      
          request(options, function (error, response, body) {
              if (!error && response.statusCode == 200) {
                  return body;
              }
          });
      };
      
      //use your function
      var body = google_request("ant", "session1")
      console.log(body); //this will return undefined
      

      以下代码有效:

      //asynchronous function
      var google_request  = function(animal_name, sessionid, callback_function){
          var options = {
              url: 'http://google.com',
              method: 'POST',
              json: {
                  "animal": animal_name,
                  "sessionid": sessionid
              }
          };
      
          request(options, function (error, response, body) {
              if (!error && response.statusCode == 200) {
                  callback_function(body);
              }
          });
      };
      
      //use your function
      google_request("ant", "session1", function(body){
          console.log(body); 
      )};
      

      这可能不是最简单的例子,但我对这个函数所做的更改非常简单;我向函数传递了第三个参数,称为“callback_function”,而不是返回“body”,而是在 body 上调用了 callback_function。然后在下面我以通常的“节点”方式使用我的函数,而不是同步方式。

      您可能还会发现此线程信息丰富:How do I return the response from an asynchronous call?

      【讨论】:

        猜你喜欢
        • 2018-09-14
        • 2016-01-02
        • 2019-12-29
        • 2015-11-18
        • 2019-01-20
        • 2019-07-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多