【问题标题】:I guess I don't "get" async programming我想我没有“得到”异步编程
【发布时间】:2013-12-19 06:38:15
【问题描述】:

我已经使用 node.js 大约 6 个月了,时断时续。但是,我想我仍然没有完全理解围绕异步调用设计程序。

以我最近的程序为例,它需要读取一个配置,使用该配置连接到数据库,然后异步连接到数据库中的每个地址。​​

我正在使用模块 fnoc 和 node-mysql,但这只是伪代码。

// first, get the config
fnoc(function(err, confs){
   // code stuff in here

   //now check that there's a database config
   if (confs.hasOwnProperty("database"))
   {
      // set up db connection
      var mysql_conn = mysql.createConnection({
          host:   confs.database.host,
          user:   confs.database.user,
          password:       confs.database.password,
          database:       confs.database.database
      });
      // do some querying here.
      mysql_conn.query(query, function(err, records, fields){
          records.forEach(function(host){
              // four levels in, and just now starting the device connections
          });
      });


   }
});

每次我写这样的东西,回调里面的回调里面的回调,我觉得我做错了什么。我知道 Promise 和异步节点库,但似乎如果这些是解决方案,它们应该是默认功能。是我做错了什么,还是只是没有为我点击?

编辑:一些建议包括使用回调函数,但这似乎更糟(除非我做错了,这是完全可能的)。你最终会在另一个函数中调用一个函数,这看起来特别像意大利面条。

上面的例子,带有函数:

function make_connection (hosts) {
hosts.foreach(function(host){
      //here's where the fun starts
    };
}


function query_db(dbinfo){
    var mysql_conn = mysql.createConnection({
          host:  dbinfo.host,
          user:  dbinfo.user,
          password:       dbinfo.password,
          database:       dbinfo.database
    });

// do some querying here.
    mysql_conn.query(query, function(err, records, fields){
    make_connection(records);
});

}



// first, get the config
fnoc(function(err, confs){
   // code stuff in here

   //now check that there's a database config
   if (confs.hasOwnProperty("database"))
   {
      // set up db connection

      query_db(confs.database);
      var mysql_conn = mysql.createConnection({
          host:   confs.database.host,
          user:   confs.database.user,
          password:       confs.database.password,
          database:       confs.database.database
      });
      // do some querying here.
      mysql_conn.query(query, function(err, records, fields){
          records.forEach(function(host){
              // four levels in, and just now starting the device connections
          });
      });


   }
});

【问题讨论】:

  • 连续传递风格(适用于此,对吗?)确实需要一些时间来适应。
  • 如果您正确地将其拆分为函数而不是试图将所有内容强制转换为一大段代码,那么“回调地狱”就变得易于管理。意大利面条代码总是一个糟糕的模式,无论是否回调。
  • 对我来说看起来不错。您可以将回调的输出和输入分开,这使得它更易于管理(并且更重要)可组合。例如,函数式反应式编程就是这样的解决方案:bacon。然后,您实际上是在构建数据流经的电路。但老实说,你也需要用大脑思考它,因为它是一个完整的范式,而不仅仅是一个库。

标签: javascript node.js asynchronous


【解决方案1】:

异步函数和回调的目的是避免对象之间的任何冲突(发生的可能比你想象的要多!)。

我想向您指出这位异步爱好者:http://www.sebastianseilund.com/nodejs-async-in-practice

是的,回调确实需要一些时间来适应,但这是值得的!

【讨论】:

  • 那个博客链接很特别,特别是因为我正在做他所说的每一个。我会用这个。
【解决方案2】:

简而言之:代替

foo(function () {
    // ... stuff #1 ...

    bar(function () {
        // ... stuff #2 ...

        baz();
    });
});

做

foo(handleFoo);

function handleFoo() {
    // ... stuff #1 ...

    bar(handleBar);
}

function handleBar() {
    // ... stuff #2 ...

    baz();
}

当然,它可以(也许应该)更细化,但这取决于实际代码。这只是一种避免嵌套函数的模式。还可以对这些方法进行更多的封装。

这是“普通”方法。还有一些库可以让您以很好的方式管理它。

【讨论】:

  • 我考虑过这一点,但我不会只是在另一个函数中调用一个函数(比如在配置读取函数中调用数据库查询函数?)?不知何故,这似乎是更糟糕的代码。
  • 如果做得对,它就不是意大利面条式的(例如,在封装步骤的“逐步模式”中)。是的,函数调用仍然是嵌套的,但这绝对没有错。您可以使用的任何库仍然会这样做,只是可能“在幕后”。我只同意使用这样的库 mit 可能 a) 更舒适 b) 外观和感觉更清洁,即使它在技术上是相同的。无论如何,适当的分离绝对不是反模式。
【解决方案3】:

如果您真的厌倦了无休止的回调,请尝试Q 或co。你可以像这样编写 node.js 代码:

co(function *(){
  var a = get('http://google.com');
  var b = get('http://yahoo.com');
  var c = get('http://cloudup.com');
  var res = yield [a, b, c];
  console.log(res);
})()

这几乎是一种不同的写作方式,因此可能难以掌握,但结果非常好。

【讨论】:

  • 是的,几个月前我和 Q 做了一些承诺。这很酷,但我觉得我应该在开始使用快捷方式之前了解事情是如何“应该”工作的。
  • @coding_hero 承诺是不是回调的快捷方式,并且工作方式完全不同。事实上,为了从 Promise 中获得最大的好处,你需要忘记所有关于回调的事情,因为在使用 Promise 时考虑任何回调都会导致绝对可怕的代码(这可能是大多数人看不到 Promise 优势的主要原因哈哈)。回调简直是低等的,任何学习它们都是浪费时间甚至有害 - 几乎所有其他语言都使用承诺进行异步而不是回调。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-29
  • 1970-01-01
相关资源
最近更新 更多