Q.fcall not working as expected and/or README misleading
See original GitHub issueSo I’ve just started working with Q on a project and want to convert a simple nested chain of callbacks into a promise chain. Things don’t quite work the way the beginning of the README suggests with its “flatten the pyramid” code example.
Let’s say I have two functions step1
and step2
like in the example:
function step1(callback) {
callback('v1 value');
}
function step2(v, callback) {
console.log("v1: " + v);
callback('v2 value');
}
We can see the expected behavior by doing a simple nested chain:
> step1(function(v1) {
... step2(v1, function(v) {
..... console.log("final value: " + v);
..... });
... });
v1: v1 value
final value: v2 value
‘v1 value’ gets printed and then ‘v2 value’.
If I then try to convert to Q in the manner shown in the README, this is the result:
> Q.fcall(step1).
... then(step2).
... then(function(v) {
... console.log("final value: " + v);
... }, function(err) {
... console.log("err: " + err.message);
... console.log(err.stack);
... }).
... done();
undefined
> err: undefined is not a function
TypeError: undefined is not a function
at step1 (repl:2:1)
at Promise.apply (/Users/dkim-m/projects/map/node_modules/q/q.js:1022:26)
at Promise.promise.promiseDispatch (/Users/dkim-m/projects/map/node_modules/q/q.js:661:41)
at /Users/dkim-m/projects/map/node_modules/q/q.js:1273:25
at flush (/Users/dkim-m/projects/map/node_modules/q/q.js:106:17)
at process._tickCallback (node.js:415:13)
step1
is getting called here but it doesn’t receive a callback.
Using deferred’s in the fullfillment handlers works:
> Q.fcall(function() {
... var def = Q.defer();
... step1(def.resolve);
... return def.promise;
... }).
... then(function(v) {
... var def = Q.defer();
... step2(v, def.resolve);
... return def.promise;
... }).
... then(function(v) {
... console.log("final value: " + v);
... }, function(err) {
... console.log("err: " + err.message);
... console.log(err.stack);
... }).
... done();
undefined
> v1: v1 value
final value: v2 value
But I really don’t want to have write all that code.
The situation with Q.nfcall
is a little better.
Let’s say I have node-style versions of step1
and step2
:
function nstep1 (callback) {
callback(null, 'v1 value');
}
function nstep2(v, callback) {
console.log("v1: " + v);
callback(null, 'v2 value');
}
And convert in a similar manner:
> Q.nfcall(nstep1).
... then(nstep2).
... then(function(v) {
... console.log("final value: " + v);
... }, function(err) {
... console.log("err: " + err.message);
... console.log(err.stack);
... }).
... done();
undefined
> v1: v1 value
err: undefined is not a function
TypeError: undefined is not a function
at nstep2 (repl:3:1)
at _fulfilled (/Users/dkim-m/projects/map/node_modules/q/q.js:703:54)
at self.promiseDispatch.done (/Users/dkim-m/projects/map/node_modules/q/q.js:732:30)
at Promise.promise.promiseDispatch (/Users/dkim-m/projects/map/node_modules/q/q.js:669:13)
at /Users/dkim-m/projects/map/node_modules/q/q.js:495:49
at flush (/Users/dkim-m/projects/map/node_modules/q/q.js:106:17)
at process._tickCallback (node.js:415:13)
The behavior is a little bit different this time. We get a little further – nstep
gets executed and it’s value propagated to nstep2
– but nstep2
is not receiving a callback. But there’s hope here because we got a little further this time so we try this:
> Q.nfcall(nstep1).
... then(function(v) {
... return Q.nfcall(nstep2, v);
... }).
... then(function(v) {
... console.log("final value: " + v);
... }, function(err) {
... console.log("err: " + err.message);
... console.log(err.stack);
... }).
... done();
undefined
> v1: v1 value
final value: v2 value
Success! This isn’t quite as nice as I was hoping for with the “flatten the pyramid” example but it’s a lot better than having to manipulate deffered’s in my then
handlers.
So I guess there’s a few (possible) issues here:
Q.fcall
doesn’t work as expected- If my expectation of how
Q.fcall
should work is wrong, the README is misleading. Q.nfcall
comes closer to my expectation, or at least to my ideal, but doesn’t fully get there.- If my expectation is wrong and
Q.fcall
andQ.nfcall
are working as expected:- Their behavior is inconsistent.
- It would be really nice if they did work that way.
Issue Analytics
- State:
- Created 10 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
I think what might need to be clarified is that this is not a matter of flattening the pyramid with your existing functions. To be adapted to the promise-style, you no longer pass callbacks, but simply return values or promises in any function. You would adapt your
step
ornstep
functions to bepstep
functions. You would only need to usedefer
,resolve
, ornf*
functions at the boundary between your promise-oriented functions and your non-promise functions. Does that make sense? What this should look like is:@domenic that works for me though, again, it would be nice if it (or something) did work the way the current text suggests 😃. although I understand that you can’t make the same assumptions about the adapted function that you can when using
Q.nfcall
so this may not be so straightforward.btw, what prompted this was I was playing around with the phantomjs node module, specifically the code sample in their README, and I was trying to flatten that pyramid using Q. the phantomjs functions take callbacks – but not node-style callbacks with an error as the first argument – so this mapped directly to the code sample that’s currently at the top of the README and so I tried to follow the example and it didn’t work. so clarifying the README would at least avoid another newbie opening the same issue in github.