cujojs / when

A solid, fast Promises/A+ and when() implementation, plus other async goodies.
Other
3.44k stars 394 forks source link

Description of .tap() method is not accurate #466

Open puncha opened 8 years ago

puncha commented 8 years ago

This is a document defect. I don't think tap() equals to the following codes:

// Using only .then()
promise.then(function(x) {
    doSideEffectsHere(x);
    return x;
});

Actually, based on my understanding, it equals to :

promise.then(function(x) {
    when(doSideEffectsHere(x)).then(function(){x;});
});
briancavalier commented 8 years ago

Hi @puncha. Good question. I'll try to explain. Let's start with your example. I tweaked it slighty, as I think you meant to return x in the inner anonymous function. I also added a console.log. You can run it in a node repl to see what it does.

var p2 = promise.then(function(x) {
    when(doSideEffectsHere(x)).then(function(){ return x;});
});

p2.then(function(y) { console.log(y); });

If you try this in node, you'll see that it logs undefined. The reason is that you've not returned anything (thus, implicitly returning undefined), from the outer then.

Going back to the original example from the docs:

var p2 = promise.then(function(x) {
    doSideEffectsHere(x);
    return x;
});

p2.then(function(y) { console.log(y); });

If you try that one in node, it will correctly log whatever the value of x was. The reason is that x is returned from the outer then. In this case, if doSideEffectsHere is synchronous then this example is indeed equivalent to promise.tap(doSideEffectsHere)

I think what you may be getting at, though, is that tap will wait for a promise returned from the function passed to it, even though it doesn't allow changing the value. IOW, the function passed to tap can delay the result, but not change its value. For example:

var p = when(123).tap(function(x) { return when(456).delay(1000); });

p.then(function(y) { console.log(y); }); // logs 123 after 1 second

Note how this example logs 123 and not 456, but still gets delayed by 1 second. So, we could add another example to the docs that clarifies this delaying ability of tap.

Finally, tap is allowed to turn a success into a failure by throwing or returning a rejected promise:

var p = when(123).tap(function(x) { throw new Error('oops!'); });

p.catch(function(e) { console.log(e.message); }); // logs 'oops!'

var p2 = when(123).tap(function(x) { return when.reject(new Error('oops!'); });

p2.catch(function(e) { console.log(e.message); }); // also logs 'oops!'

I hope that helps to clarify :)