node.js数据库查询顺序

node.js database queries in order

我想按顺序执行查询,但我不知道什么是最好的方法。

假设我想执行以下操作:

if (name) {
  //first query
  db.query({name:name}).exec(function(err,result) {
  //save result
  })
}
if (isEmpty(result)) {
  //make another query
  db.query({anotherField:value}).exec(function(err,result) {
  //save result
  })
}

我应该在这种情况下使用 promises 吗?

这将是 cakePHP 的示例:

if (!isset($field1)) {
  $result = $this->item->find( ... conditions => ... = $field2);
} else {
  if (!isset($field2)) {
    $result = $this->item->find( ... conditions => ... = $field1);
  } else {
    $result = $this->item->find( ... conditions => ... = $field1 && ... =$field2);
    if (empty($result)) {
      $result = $this->item->find( ... conditions => ... =$field2);
    }
  }  
}

Promises 很适合这个,q 库是最常见的。您可能只想像这样嵌套您的承诺:

var q = require('q');

if (name) {
  //first query
  q.ninvoke(db.query({name:name}), 'exec')
  .then(function(result) {
    //save result
    if (isEmpty(result)) {
      //make another query
      q.ninvoke(db.query({anotherField:value}), 'exec')
      .then(function(result) {
        //save result
      })
      .fail(function(err) {
        //handle failure
        console.error(err, err.stack);
      });
    }
  })
  .fail(function(err) {
    //handle failure
    console.error(err, err.stack);
  });
}

q.ninvoke 允许我们将标准的 nodejs 函数转换为它们的 promise 等价物。

如果您的意思是 "in order",您可以嵌套回调。传递回调是构造异步代码的经典(非承诺)方式:

function doMultipleAsyncThings(name, callback){
  if (name) {
    //first query
    db.query({name:name}).exec(function(err,result) {
      if (isEmpty(result)) {
        //make another query
        db.query({anotherField:value}).exec(function(err,result) {
          //save result
        })
      } else {
        //save result
      }
    })
  } else {
    return callback('no name');
  }
}

注意,经过 2 次左右的操作后,您最终会得到 'callback hell' 100 多行嵌套代码,async 库对此很有帮助:

var async = require('async');
doMultipleAsyncThings('plato', function(){
  console.log(arguments)
});

function doMultipleAsyncThings(name, callback){
  // `callback` is a passed-in function to call after doMultipleAsyncThings is done
  // Here, it is the function we passed in above after 'plato'
  async.waterfall([function(done){
      done(null, name);
    },
    firstQuery,
    secondQuery,
  ], callback)
}

function firstQuery(name, done){
  if (name) {
    // You can define and pass a callback inline:
    db.query({name:name}).exec(function(err,result) {
      done(err, result);
    })
  } else {
    done('no name');
  }
}

function secondQuery(result, done){
  if (isEmpty(result)) {
    // You can pass a callback by reference:
    db.query({anotherField:value}).exec(done)
  } else {
    //save result
    done();
  }
}