【问题标题】:Two Asynchronous Functions in JavaScript (Node.js)JavaScript (Node.js) 中的两个异步函数
【发布时间】:2014-08-16 09:27:14
【问题描述】:

我有一个异步的数据库查询(函数),因此我需要使用回调函数(没问题)。但是,在 Node.js 中,我需要在同一个 POST 函数中进行两个单独的查询。两者都是异步的,所以我在如何继续执行 POST 时遇到了麻烦。

目标:

  1. 验证表单条目是否存在畸形等
  2. 保存前检查数据库中是否存在用户名(必须唯一)
  3. 保存前检查数据库中是否存在电子邮件(必须是唯一的)
  4. 如果一切都检查成功,则保存用户,否则会引发一些错误

通常,我会有这样的东西(过于简单):

postSearch = function(req, res, next) {

  var searchCallback = function(err, results) {
    // Do stuff with the results (render page, console log, whatever)
  }
  // This is the db query - async. Passes search results to callback
  defaultSearch(input, searchCallback);
}

只有一个异步查询,所以只有一个回调。通常我只会得到数据库结果并呈现一个页面。现在我必须验证一些表单数据,所以我的 POST 函数看起来像这样:

postUser = function(req, res, next) {

  // Some static form validation (works, no issues)

  var usernameExistsCallback = function(err, exists) {
    // Does the username exist? True/false
  }
  // DB query - passes true or false to the callback
  usernameExists(username, usernameExistsCallback);

  var emailExistsCallback = function(err, exists) {
    // Does the email exist? True/false
  }
  // DB query - passes true or false to the callback
  emailExists(email, emailExistsCallback);

  // Check if ALL validation constraints check out, implement error logic
}

node-postgres 模块是异步的,因此查询需要回调(如果我想返回任何值,否则我可以运行查询并断开连接)。我执行这两个查询都没有问题。我可以在回调中console.log() 正确的结果。但现在我不知道以后如何在 postUser 函数中访问这些结果。

我已经阅读了所有关于异步 JavaScript 函数的内容,但是我已经在这方面摸索了三个小时,现在正在尝试一些荒谬的事情(比如设置 全局变量 [oh my!])没用。

我需要的这两个查询的结果只是truefalse。如何组织此代码以便能够在 postUser 函数中使用这些结果?在我看来,我需要类似 third 回调的东西,但我不知道如何实现类似的东西。我有必要开始使用async吗?这会是个好主意吗?到目前为止,这个应用程序中没有什么是超级复杂的,我想保持低依赖这是有道理的。

【问题讨论】:

    标签: javascript node.js postgresql asynchronous


    【解决方案1】:

    您可以使用一个通用变量来跟踪您收到了多少回复。如果你同时拥有它们,那么你可以在第三个“回调”中完成需要它们的事情,我称之为 done():

    postUser = function(req, res, next) {
    
      var hops=0, total=2;
    
       function done(){
           // do stuff with both username and email
       }
    
      // Some static form validation (works, no issues)
    
      var usernameExistsCallback = function(err, exists) {
        if(++hops>=total && exists ){ done(); }
        // Does the username exist? True/false
      }
      // DB query - passes true or false to the callback
      usernameExists(username, usernameExistsCallback);
    
      var emailExistsCallback = function(err, exists) {
        if(++hops>=total && exists){ done(); }
        // Does the email exist? True/false
      }
      // DB query - passes true or false to the callback
      emailExists(email, emailExistsCallback);
    
      // Check if ALL validation constraints check out, implement error logic
    }
    

    您可能应该根据您的应用程序的需要添加错误处理,特别是在两个 SQL 回调中,但这是一个很好的并行 IO ajax 模式,应该可以满足您的需要。

    【讨论】:

    • 我很快就会测试它!我要参加一个会议,所以我稍后会告诉你这是怎么回事。不过看起来很有希望:) 快速的问题 - 使用这种逻辑,我会在回调中构建错误并将它们传递给done()吗?或者我会假设当done() 被调用时这两个字段被验证(因为否则我会在原始回调中已经呈现一些错误)?无论如何,我很快就会使用它,看看有什么用。
    • 这种模式的优点是两个 SQL 请求同时执行并且避免了嵌套。您可以通过任何一种方式处理错误:在“旧”回调中单独处理,或者通过将错误向前传递 ala done(theErrorOrResponse),并在那里处理所有内容。如果您已经进行了错误处理,那么将它们留在原处可能最容易。如果您需要添加错误处理,我会将所有内容传递给 done(),也许会像许多节点一样使 done 的参数:回调 done(err, resp)。
    • 我认为将参数传递给done() 是最有意义的。对我而言,done() 意味着 已完成所有验证步骤,是时候呈现带有结果的页面了:successfailure 结果是取决于验证是否签出。我认为这种方法更有意义,特别是因为我可以在done() 中构建所有错误的列表并根据该列表正确呈现页面。我很快就会看看一个真正的实现,但现在我必须去签署一份租约。我会让你知道这个策略的效果:)
    • 几天前我说尽快测试一下...我想我有点夸张了!好吧,我已经修改了你的想法,它完美地运行。不得不说,这真是太聪明了!我认为我可能会经常使用这种模式 :) 很酷的部分是,我可以在数据库回调中使用 req.flash(param, message) ,而不是将错误传递给处理函数,这些稍后可以在done()。这似乎是对需要数据库查找的表单验证进行错误处理的一种非常简洁的方法。非常非常好,谢谢!
    【解决方案2】:

    这个怎么样:

    postUser = function(req, res, next) {
        // Some static form validation (works, no issues)
    
        var emailExistsCallback = function(err, exists) {
            // Does the email exist? True/false
            var usernameExistsCallback = function(err, exists) {
                // Does the username exist? True/false
                // DO STUFF HERE
            }
            // DB query - passes true or false to the callback
            usernameExists(username, usernameExistsCallback);
        }
        // DB query - passes true or false to the callback
        emailExists(email, emailExistsCallback);
    
        // Check if ALL validation constraints check out, implement error logic
    }
    

    【讨论】:

    • 我考虑过这样做,但我认为它会真的令人困惑......我需要进行一些错误处理,并且像那样过于嵌套是强硬(imo)。我会尝试这两种解决方案,看看哪种看起来/感觉最好:)
    • 你也可以使用 Promise。我没有在 node 中编程太多,但我刚刚在 python/txpostgres 中完成了一个项目,这是异步调用。我有一些查询,我必须连续运行 8 次才能知道结果。对于那些我使用 deferreds 的,我不知道你是否在 node 中有那些?
    • 我相信 promises 和 defereds 在 Node.js 中是一个东西。我记得最近读过它们,尽管我没有特别看到它们有什么用处。使用当前的规范,项目中的任何事情都不会变得足够复杂,因为查询这些技术是必要的。我最复杂的事情是在 POST 中运行这两个查询 - 大多数 POST 只运行一个查询,结果简单直接,所以还不需要那些东西:P
    【解决方案3】:

    最简单的方法是像这样嵌套函数:

    postUser = function(req, res, next) {
      var emailExistsCallback = function(err, exists) {
        // Does the email exist? True/false
    
        // Check if ALL validation constraints check out, implement error logic
        next(); // <= you should finally call "next" callback in order to proceed
      }
      var usernameExistsCallback = function(err, exists) {
        // Does the username exist? True/false
        emailExists(email, emailExistsCallback); // <= note this
      }
      usernameExists(username, usernameExistsCallback);
    }
    

    或者您可以使用asyncQseqyaff(Seq 重新实现)。有许多库可以让您的生活更轻松。最好全部尝试一下,然后根据您的风格、要求等决定哪一种适合您。

    【讨论】:

    • 我考虑过使用 async,因为我可能可以通过单个回调并行运行这些(不确定,不太了解 async)。但我想保持较低的依赖关系,并尽可能避免不必要的依赖。
    • 没关系。但是,您必须处理嵌套回调,这在某些时候可能会成为一场噩梦。
    • 我同意——这就是我考虑使用它的原因;)我迄今为止最复杂的一组回调就是这个。我想我将来最终会使用异步,我只是在必要之前不想使用它:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    • 2019-01-20
    • 2017-06-01
    • 2023-02-05
    • 2016-08-17
    • 1970-01-01
    相关资源
    最近更新 更多