NodeJS Promise (Q) - How to get a value if the promise fails?

javascript, node.js, promise, q

Solution

I recommend this approach:

return makeImage().then(function (path) {
    return doSomeCoolThings(path)
    .finally(function () {
        return removeImage(path);
    });
});

Assuming you trust makeImage, removeImage, and doSomeCoolThings to return Q promises and never throw. Otherwise, there’s always `Q.fcall` which eliminates these concerns.

If you wish to retain the image in the success case, and only delete it if there’s a failure, rethrowing the error:

return Q.fcall(makeImage).then(function (path) {
    return Q.fcall(doSomeCoolThings, path)
    .catch(function (error) {
        return Q.fcall(removeImage, path)
        .thenReject(error);
    });
});

Also, instead of:

var deferred = Q.defer();
deferred.resolve(x);
return deferred.promise;

You can:

return Q.resolve(x);

Problem

I´m starting to use promises in my NodeJS projects and I run into a problem. After I read the Promises/A+ spec and googling a lot I didn´t find a nice solution for the case that I need to access a value which gets produced in a promise chain. In my example I want to check when an error occurs if the image was created and if so, I want to delete it. Code: ``` var Q = require('Q'); var fs = require('fs'); // This produces the imgPath function makeImage() { var deferred = Q.defer(); deferred.resolve("path/to/image"); return deferred.promise; } function watermark(imgPath) { var deferred = Q.defer(); deferred.resolve(imgPath); return deferred.promise; } // This function fails function doSomeCoolThings(imgPath) { var deferred = Q.defer(); deferred.reject(new Error("System is exploded")); return deferred.promise; } var fileExists = Q.denodeify(fs.readFile); var deleteFile = Q.denodeify(fs.unlink); // How do I get the imgPath here? function deleteImageIfPresent(err) { return Q.fcall(function () { return imgPath !== undefined; }) .then(fileExists) .then(deleteFile); } var iKnowThatSolution; makeImage() // Thats not what I want //.then(function(imgPath) { // iKnowThatSolution = imgPath; //}) .then(watermark) .then(doSomeCoolThings) .fail(deleteImageIfPresent); ```

Original source