【问题标题】:node-postgres 'event emitter style' vs 'callback style'node-postgres“事件发射器样式”与“回调样式”
【发布时间】:2016-05-14 19:20:40
【问题描述】:

node-postgres 声明如下:

node-postgres 支持“事件发射器”样式 API 和“回调”样式。这 回调风格更简洁,一般首选,但事件 API 可以进来 便利。它们可以混合搭配。

使用事件发射器 API,我可以执行以下操作:

var db = new pg.Client("insert-postgres-connection-info");
db.connect();

然后我可以使用db 在整个网络应用程序中使用db.query('sql statement here') 执行查询。使用回调样式,每次我想运行查询时都会执行以下操作:

pg.connect(conString, function(err, client) {
  client.query("sql statement", function(err, result) {
    // do stuff
  });
});

所以我的问题是为什么“通常首选”使用回调样式?每次对数据库做某事时打开一个连接不是效率低下吗?使用回调样式有什么好处?

编辑

我可能会误解他所说的“回调样式”是什么意思(我不是在开玩笑,我的 JavaScript 不是很强大),但我的问题是关于连接方法。我假设以下是回调样式连接方法:

// Simple, using built-in client pool

var pg = require('pg'); 
//or native libpq bindings
//var pg = require('pg').native

var conString = "tcp://postgres:1234@localhost/postgres";

//error handling omitted
pg.connect(conString, function(err, client) {
  client.query("SELECT NOW() as when", function(err, result) {
    console.log("Row count: %d",result.rows.length);  // 1
    console.log("Current year: %d", result.rows[0].when.getYear());
  });
});

以下是EventEmitter API的连接方法:

// Evented api
var pg = require('pg'); //native libpq bindings = `var pg = require('pg').native`
var conString = "tcp://postgres:1234@localhost/postgres";

var client = new pg.Client(conString);
client.connect();

如果我只是在这里混淆了术语,我的问题仍然存在。 pg.connect(do queries) 每次使用时都会打开一个新连接(不是吗?)而

var client = new pg.Client(conString);
client.connect();

打开一个连接,然后允许您在必要时使用client 运行查询,不是吗?

【问题讨论】:

    标签: node.js postgresql node-postgres


    【解决方案1】:

    EventEmitter 风格更适合这种类型的东西:

    var query = client.query("SELECT * FROM beatles WHERE name = $1", ['John']);
    query.on('row', function(row) {
      console.log(row);
      console.log("Beatle name: %s", row.name); //Beatle name: John
      console.log("Beatle birth year: %d", row.birthday.getYear()); //dates are returned as javascript dates
      console.log("Beatle height: %d' %d\"", Math.floor(row.height/12), row.height%12); //integers are returned as javascript ints
    });
    

    通过混合搭配,你应该可以做到以下几点:

    // Connect using EE style
    var client = new pg.Client(conString);
    client.connect();
    
    // Query using callback style
    client.query("SELECT NOW() as when", function(err, result) {
      console.log("Row count: %d",result.rows.length);  // 1
      console.log("Current year: %d", result.rows[0].when.getYear());
    });
    

    请注意,即使使用回调样式,也不会在每次要执行查询时都打开连接;最有可能的是,您会在应用程序启动时打开一个连接并在整个过程中使用它。

    【讨论】:

    • 根据您的回答编辑了我的问题。
    • 查看源码,貌似模块缓存了与数据库的连接;所以即使你多次调用pg.connect,你实际上得到的是相同的连接(或者,实际上,one in a pool of connections)。
    • 这更有意义。感谢您的帮助。
    • 如何在变量中返回结果?我可以用 console.log 显示,但我不能返回它们
    【解决方案2】:

    有利有弊,您选择哪一种取决于您的用例。

    用例一:将结果集逐行返回给客户端。

    如果您要以与从数据库中返回数据的方式(逐行)大致相同的方式将数据返回给客户端,那么您可以使用事件发射器样式来减少延迟,我在这里将其定义为之间的时间发出请求并接收第一行。如果您改用回调样式,则会增加延迟。

    用例 2:根据整个结果集返回分层数据结构(例如 JSON)。

    如果您要以 JSON 等分层数据结构向客户端返回数据(当结果集是层次结构的平面表示时,您会这样做以节省带宽),您应该使用回调样式,因为在收到所有行之前,您无法返回任何内容。您可以使用事件发射器样式并累积行(node-postgres 提供了这样的机制,因此您不必通过查询维护部分构建结果的映射),但这将是无意义的浪费,因为您不能在收到最后一行之前返回任何结果。

    用例 3:返回分层数据结构数组。

    当返回一个分层数据结构数组时,如果您使用回调样式,您将有很多行需要一次全部通过。这会阻塞很长一段时间,这是不好的,因为您只有一个线程来服务许多客户端。因此,您应该将事件发射器样式与行累加器一起使用。您的结果集应该这样排序,以便当您检测到特定字段的值发生变化时,您知道当前行代表要返回的新结果的开始,并且到目前为止累积的所有内容都代表现在完整的结果,您可以将其转换为您的分层表格并返回给客户端。

    【讨论】:

      猜你喜欢
      • 2022-01-21
      • 1970-01-01
      • 2019-06-29
      • 2016-08-01
      • 2020-07-06
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多