Skip to content

Instantly share code, notes, and snippets.

@jergason
Created November 20, 2012 15:42
Show Gist options
  • Select an option

  • Save jergason/4118701 to your computer and use it in GitHub Desktop.

Select an option

Save jergason/4118701 to your computer and use it in GitHub Desktop.
Promises vs nested callbacks?
// Assume the error handling logic is pretty different at each async step,
// and I have multiple different error conditions that require different
// actions to handle them.
// How can I do this with promises without passing some kind of additional
// data to the error handler so it can know what logic to use?
function someFattyAsyncThing(data, cb) {
someAsyncOp(data, function (err, res) {
if (err) {
return cb(err);
}
else if (res.someProp == 'beans') {
return cb(new Error('some tricky error handling logic'));
}
someOtherAsyncOp(res, function (err, res) {
if (err) {
return cb(err);
}
else if (res.length < 100) {
return cb(new Error('some slightly different error'));
}
return cb(null, res);
});
});
}
function withPromises(data) {
var d = Q.defer();
someAsyncOp(data, function(err, res) {
if (err || res.someProp == 'beans') {
return d.reject([err, res]);
}
d.resolve(res);
});
return d;
}
function nextStep(data) {
var d = Q.defer();
someOtherAsyncOp(data, function (err, res) {
if (err || res.length < 100) {
return d.reject([err, res]);
}
d.resolve(res);
});
return d
}
withPromises(data).then(nextStep).then(function(data) {
// wahoo
},
function (errors) {
// now I have to duplicate my error-checking logic to see what step
// actually threw the error and take the correct actionn
}).done();
@domenic
Copy link
Copy Markdown

domenic commented Nov 20, 2012

This would be my first instinct:

withPromises(data)
.then(
    nextStep,
    function (step1Error) {
    })
.then(
    function (data) {
    },
    function (step2Error) {
    }
).done();

A point, though: remembering that promises are about sync-async equivalence, what would you expect this code to look like in a sync manner? For example, I doubt you'd ever do throw [err, res]; so why reject with that? For that matter, why aren't you rejecting with the same errors you callback with in the someFattyAsyncThing code?

Maybe what you're looking for is something more like this?

var someAsyncOpP = Q.nbind(someAsyncOp);
var someOtherAsyncOpP = Q.nbind(someOtherAsyncOp);

function withPromises(data) {
    return someAsyncOpP(data).then(function (res) {
        if (res.someProp === "beans") {
            throw new Error("someProp was beans");
        }
    });
}

function nextStep(data) {
    return someOtherAsyncOpP(data).then(function (res) {
        if (res.length < 100) {
            throw new Error("length < 100");
        }
    });
}

withPromises(data).then(nextStep).done();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment