使用 Node.js 和 Postgresql 在没有回调的函数中调用数据库

Database call in a function without callback with Node.js and Postgresql

我正在我的一个项目中试用框架 node.js。 我真的看到了他们所谓的 "event-driven, non-blocking I/O model" 的一些好处,但是如果我的项目有一些时刻我不一定想要进行一些异步调用并且能够在启动一些异步调用之前进行多个操作。

特别是当我想做一些因式分解和创建一些函数时。

通常我有以下情况: 我知道在我的程序的几个部分中,我必须检查我的数据库中是否存在给定字符串或 ID 的媒体。

因此,作为一个试图保持井井有条的人,我想创建一个函数,每次我需要检查它时都会调用它。 但是,我没有找到使用 node.js 和 pg(npm PostgreSQL 库 (https://github.com/brianc/node-postgres/) 来做到这一点的方法。事实上,函数中总是有一个回调,而 return 是null 因为回调。下面是一个例子

/*
    Function which is supposed to check if a media existing
 */
function is_media_existing (url_or_id){
    log.debug("is_media_existing : begin of the function", {"Parameter" : url_or_id});
    pg.connect(connectionstring, function (err, client, done) {
        if (err) {
            log.warning("is_media_existing : Problem with Database connection", {
                "Parameter": url_or_id,
                "Error": err
            });
        }
        if (isNaN(url_or_id)) {
            // Case is parameter is not a number (string)
            var query = client.query('SELECT COUNT(*) as count FROM media WHERE url = ::string ', url_or_id);
            query.on('error', function (error) {
                log.warning("is_media_existing : Problem with Database query (connection to db passed but not query " +
                    "", {"Parameter": url_or_id, "Error": error});
            });
            return query;
        } else {
            // Case is parameter is a int
            log.debug("is_media_existing : Type of Parameter is a string");
            // Case is parameter is not a number (string)
            var query = client.query('SELECT COUNT(*) as count FROM media WHERE id = ::id ', url_or_id);
            query.on('error', function (error) {
                log.warning("is_media_existing : Problem with Database query (connection to db passed but not query " +
                    "", {"Parameter": url_or_id, "Error": error});
            });
            return query;
        }
    });
}


// Executing the function 
var test = is_media_existing("http://random_url_existing_in_db");
// test is always null as the return is in a callback and the callback is asynchronous 

感觉我的问题触及了node.js的核心概念,可能是我的做法不对,提前致歉。 我知道在做某事之前等待响应是不好的。 但是有什么选择呢?当我的代码的多个部分需要某些功能时,如何将我的代码分解为函数?

因此,如果有人可以通过最佳编程实践来解释如何做到这一点,那就太好了。

谢谢

安塞尔姆

有了新的 ES6 加上异步的东西和 babel 就更简单了。您可以 npm i -g babel npm i babel-runtime 然后编译 运行 以下 babel test.js --optional runtime --stage 2 | node。请仔细阅读以下示例,了解如何使其适应您的用例:

let testData = [                                                
  { id: 0, childIds: [1,2]},                                    
  { id: 1, childIds:[] }                                   
];                                                              

function dbGet(ids) {                                           
  return new Promise( r=> {
    // this an example; you could do any db
    // query here and call r with the results                                    
    r(ids.map((id) => { return testData[id];}));
  });                                                           
}

async function dbExists(ids) {                              
  let found = await dbGet(ids); 
  return (found && found.length>0);                                               
}                                                               

async function test() {                                         
  var exists = await dbExists([0]);                              
  console.log(exists);                      
}                                                               

test().then(f=>{}).catch( e=> {console.log('e',e)});            

我不认为你真的想要同步调用。节点中同步调用的问题在于它会阻止整个进程执行 anything 而同步函数是 运行 因为它将停止事件循环。例如,假设您的同步功能需要 2 秒才能完成。然后您的服务器将什么都不做 整整 2 秒。这 2 秒包括 一切(接受新连接,其他一切,等等)。阻塞函数不存在的原因是它们(非常)不好。这是一个示例,您的函数将如何在异步庄园中做出反应。

is_media_existing("http://random_url_existing_in_db", function(exists){
  if (exists){
    //do stuff
  } else {
    //do this other stuff
  }
});

然后在 is_media_existing 内,您需要在查询完成时调用该回调函数。

//psuedo
function is_media_existing(url, callback){
  query('select COUNT(*) as count FROM media WHERE id = ::id '. [url], function(err, result){
    if (err)
      callback(false)
    else
      callback(result.count > 0)
  })
}

正如 Cody 所说,您可能不想执行同步功能。

在你的示例中你应该处理这种情况的方式是像这样传递你自己的回调

function is_media_existing (url_or_id, callback){

然后像这样使用回调而不是 return query;-

callback(query);

或者最好遵循回调函数的节点约定,使其具有两个参数(err, result),这样您的回调将如下所示

callback(null, query);

这是您的样本的返工

function is_media_existing (url_or_id, callback){       /* callback(err, result) */
    log.debug("is_media_existing : begin of the function", {"Parameter" : url_or_id});
    pg.connect(connectionstring, function (err, client, done) {
        if (err) {
            done(err);
            log.warning("is_media_existing : Problem with Database connection", {
                "Parameter": url_or_id,
                "Error": err
            });
            return callback(err, null);     
                /* note that this return is simply used to exit the connect's callback and the return value is typically 
                 * not used it is the call to callback() that returns the error value */
        } 
        var qrystr;

        if (isNaN(url_or_id)) {
            log.debug("is_media_existing : Type of Parameter is a string");
            qrystr = 'SELECT COUNT(*) as count FROM media WHERE url = ::string;';
        } else {
            qrystr = 'SELECT COUNT(*) as count FROM media WHERE id = ::id;';
        }
        client.query(qrystr, [url_or_id], function(err, result){
            done();
            if(err){
                /* .. */
            }
            callback(err, result);
        });
    });
}


// Executing the function 
var test = is_media_existing("http://random_url_existing_in_db", function(err, result){
    if(err){

    }else {

    }
});

如果您最终遇到一堆回调,那么 promises 确实值得研究。