node-postgres states the following:
node-postgres supports both an 'event emitter' style API and a 'callback' style. The callback style is more concise and generally preferred, but the evented API can come in handy. They can be mixed and matched.
With the event emitter API, I can do the following:
var db = new pg.Client("insert-postgres-connection-info");
db.connect();
And then I can use db
to execute queries throughout my web app using db.query('sql statement here')
. With the callback style, I would do the following each time I want to run a query:
pg.connect(conString, function(err, client) {
client.query("sql statement", function(err, result) {
// do stuff
});
});
So my question is why is it "generally preferred" to use the callback style? Isn't it inefficient to open a connection each time you do something with the database? What benefits are there from using the callback style?
EDIT
I might be mistaken as to what he means by "callback style" (I'm not kidding, my JavaScript isn't very strong) but my question is about the method of connection. I assumed the following was the callback style connection method:
// 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());
});
});
and the following is the EventEmitter API connection method:
// 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();
If I'm just getting terms mixed up here, my question still remains. pg.connect(do queries)
opens a new connection every time you use it (doesn't it?) whereas
var client = new pg.Client(conString);
client.connect();
opens a connection and then allows you to use client
to run queries when necessary, no?
The EventEmitter style is more for this type of thing:
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
});
By mixing and matching, you should be able to do the following:
// 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());
});
Note that even when using the callback style, you wouldn't open a connect every time you want to execute a query; most likely, you'd open a connection when the application starts and use it throughout.
There are pros and cons and the one you choose depends on your use case.
If you're going to return data to the client much in the same way it comes out of the database - row by row - then you can use the event emitter style to reduce latency, which I define here as the time between issuing the request and receiving the first row. If you used the callback style instead, latency would be increased.
If you're going to return data to the client in a hierarchical data structure such as JSON (which you would do to save bandwidth when the result set is a flat representation of a hierarchy), you should use the callback style because you are can't return anything until you have received all rows. You could use the event emitter style and accumulate rows (node-postgres provides such a mechanism so you don't have to maintain a map of partially built results by query), but it would be a pointless waste of effort because you can't return any results until you have received the last row.
When returning an array of hierarchical data structures, you will have a lot of rows to get through all at once if you use the callback style. This would block for a significant amount of time which isn't good because you have only one thread to service many clients. So you should use the event emitter style with the row accumulator. Your result set should be ordered such that when you detect a change in value of a particular field, you know the current row represents the beginning of a new result to return and everything accumulated so far represents a now complete result which you can convert to your hierarchical form and return to the client.