5

I want to make sure I am not missing a trick; in Kris Kowal's library, you can do the following as a generic catch statement in promises:

var a, b, c, d, e, f;

readFile('fileA')
    .then(function (res) {
        a = res;

        return readFile('fileB');
    })
    .then(function (res) {
        b = res;

        return readFile('fileC');
    })
    .then(function (res) {
        c = res;

        return readFile('fileD');
    })
    .then(function (res) {
        d = res;

        return readFile('fileE');
    })
    .then(function (res) {
        e = res;

        return readFile('fileF');
    })
    .then(function () {
        f = res;
    })
    .catch(function () {
        // error happened in file read *somewhere* (don't care where)
    });

In jQuery's deferred objects, there is no catch statement, instead, I have to do this:

var a, b, c, d, e, f;

readFile('fileA')
    .then(function (res) {
        a = res;

        return readFile('fileB');
    })
    .fail(function () {
        // error happened in file read *somewhere* (don't care where)
    })
    .then(function (res) {
        b = res;

        return readFile('fileC');
    })
    .fail(function () {
        // error happened in file read *somewhere* (don't care where)
    })
    .then(function (res) {
        c = res;

        return readFile('fileD');
    })
    .fail(function () {
        // error happened in file read *somewhere* (don't care where)
    })
    .then(function (res) {
        d = res;

        return readFile('fileE');
    })
    .fail(function () {
        // error happened in file read *somewhere* (don't care where)
    })
    .then(function (res) {
        e = res;

        return readFile('fileF');
    })
    .fail(function () {
        // error happened in file read *somewhere* (don't care where)
    })
    .then(function (res) {
        f = res;

        return readFile('fileF');
    })
    .fail(function () {
        // error happened in file read *somewhere* (don't care where)
    });

Unfortunately, each then branch has unique logic. Am I missing something, or is the jQuery variation above the only way to achieve the equivalent in Kris Kowal's q library?

keldar
  • 6,152
  • 10
  • 52
  • 82
  • 1
    Did you try chaining `then()` and using a single `.fail();` at the end? it should work. – T J Dec 16 '15 at 18:02
  • This is typical question for Sebastien, im still not sure than you can replace catch by fail – A. Wolff Dec 16 '15 at 18:10
  • @A.Wolff ah.. Who Sebastien..? another wolf..? ._. – T J Dec 16 '15 at 18:16
  • @TJ oops, i meant [benjamin](http://stackoverflow.com/users/1348195/benjamin-gruenbaum)... – A. Wolff Dec 16 '15 at 18:20
  • I did, unfortunately it didn't work. Does the error propagate through the chain then? – keldar Dec 16 '15 at 19:36
  • Hey - I have updated the example to clarify my core problem; I apologise for confusion caused before. I hope this clarifies. – keldar Dec 16 '15 at 21:17
  • 2
    @keldar, part of the problem is that jQuery added Deferreds before Promises/A+ was standardized (and my understanding is that much of the standardization came on the heels of developers learning to use promise-like behavior from jQuery's deferreds). Fortunately [jQuery 3 will be Promises/A+ compatible](https://blog.jquery.com/2015/07/13/jquery-3-0-and-jquery-compat-3-0-alpha-versions-released/). – zzzzBov Dec 16 '15 at 21:20
  • @zzzzBov - thanks! This helps a great amount. – keldar Dec 16 '15 at 21:22
  • 2
    In a nutshell, jQuery's `.fail()` doesn't catch and can't be made to catch. The chain is guaranteed to remain on its error path after a `fail()`. On the other hand, the error handler of a `.then()` won't *automatically* catch but can be made to do so by returning a resolved promise; returning anything other than a resolved promise will change the "reason for failure" propagated down the error path. – Roamer-1888 Dec 16 '15 at 22:22
  • @keldar: What does your `readFile` return? A jQuery deferred? – Bergi Dec 17 '15 at 02:10
  • Btw, you should have a read of [How do I access previous promise results in a .then() chain?](http://stackoverflow.com/q/28250680/1048572). Your current approach [is horrible](http://stackoverflow.com/a/28250700/1048572) :-) – Bergi Dec 17 '15 at 02:15
  • Thanks guys. @Bergi - yes it does. AWesome - I will take a read now! – keldar Dec 17 '15 at 08:05

1 Answers1

3

Assuming readFile returns a promise object, You can actually load all the files asynchronously using $.when() (of cource if you don't care about the order in which files are read):

From the docs:

In the case where multiple Deferred objects are passed to jQuery.when(), the method returns the Promise from a new "master" Deferred object that tracks the aggregate state of all the Deferreds it has been passed. The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected. If the master Deferred is resolved, the doneCallbacks for the master Deferred are executed. The arguments passed to the doneCallbacks provide the resolved values for each of the Deferreds, and matches the order the Deferreds were passed to jQuery.when()

(emphasis mine)

$.when(readFile('fileA'), readFile('fileB'), readFile('fileC'), readFile('fileD'), readFile('fileE'), readFile('fileF'))
.then(function(a, b, c, d, e, f) {
    // big success
},function() {
    // error happened in file read *somewhere* (don't care where)
});
T J
  • 42,762
  • 13
  • 83
  • 138
  • Run them in parallel, not sequential order – A. Wolff Dec 16 '15 at 18:07
  • Looking at their documentation, I surely can do `$.when(readFile('fileA'), readFile('fileB'), ..., readFile('fileF')).then(function (a, b, ..., f) {...});` where `a, b, ..., f` are the contents of the files? – keldar Dec 16 '15 at 21:21
  • @keldar yes, updated the answer for clarity. note than your `readFile` method should return a deferred object. – T J Dec 17 '15 at 05:37
  • Thanks @TJ. Agreed - it does (or a deferred promise in fairness). – keldar Dec 17 '15 at 08:04