Promise with q structure and callback pattern in Node.js?

Even if a well-documented q framework is pretty hard to understand if you have been programming with Node.js for several days. But I like to know about it!

var Q = require('q'); var fs = require('fs'); // Make the promise manually (returns a value or throws an error) var read1 = fs.readFile(fname, enc, function (err, data) { if(err) throw err; return data; }); // Convenient helper for node, equivalent to read1? var read2 = Q.nfbind(fs.readFile); // Uh?! var read3 = function (fname, enc) { var deferred = Q.defer(); fs.readFile(fname, enc, function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); } return deferred.promise; }); }; // Execute Q.fncall(read1).then(function (data) {}, function (err) {}).done(); 

Are read1 , read2 and read3 equivalent? Can I use Q.nfbind every time the last parameter of a function receives a callback in the style of function (err, value) ?

+4
source share
1 answer

You have some errors in your examples.

READ1

This is not a β€œmake a promise by hand”, it is just a normal asynchronous call. In your code, you call readFile immediately, so read1 will be the return value of readFile , which is undefined . To get behavior like read2 and read3 , you need to do something like this:

 var read1 = function(fname, env, success, error){ fs.readFile(fname, enc, function (err, data) { // Throwing here would just crash your application. if(err) error(err); // Returning from inside 'readFile' does nothing, instead you use a callback. else success(data); }); }; 

read2

 // Not equivalent to read1 because of the notes above, // Equivalent to read3, with the fixes I mention below. var read2 = Q.nfbind(fs.readFile); 

read3

 var read3 = function (fname, enc) { var deferred = Q.defer(); fs.readFile(fname, enc, function (error, text) { if (error) { // 'error' is already an error object, you don't need 'new Error()'. deferred.reject(error); } else { deferred.resolve(text); } // HERE: Again returning a value from 'readFile' does not make sense. return deferred.promise; }); // INSTEAD: Return here, so you can access the promise when you call 'read3'. return deferred.promise. }; 

You can really use nfbind for anything that takes a callback as the last parameter. With my comments, read2 and read3 accomplish the same purpose, which is to create a function that will take a file name and encoding and return a promise object.

For this you can do this:

 read2('file.txt', 'utf8').then(function (data) {}, function (err) {}).done(); read3('file.txt', 'utf8').then(function (data) {}, function (err) {}).done(); 

For read1 , you would call it like this:

 read1('file.txt', 'utf8', function (data) {}, function (err) {}); 

Update

The promises standard has changed a bit since it was answered, and if you are leaning towards read3 , I would recommend doing the following:

 var read4 = function (fname, enc) { return Q.promise(function(resolve, reject){ fs.readFile(fname, enc, function (error, text) { if (error) { // 'error' is already an error object, you don't need 'new Error()'. reject(error); } else { resolve(text); } }); }); }; 

This is more in line with the ES6 promises standard and the blue bird, so it will be easier for you to move forward. Using the method mentioned in read3 , the ability to synchronously throw exceptions instead of catching them in the promise chain is also introduced, which is usually undesirable. See delayed antipattern .

+11
source

All Articles