Question

I'm new to the when.js javascript library, but I'm familiar with async programming in C#. That's why I find this code to be unwieldy:

filters.doFilter('filter1name', reqAndPosts).then(function(filter1) {
    filters.doFilter('filter2name', filter1).then(function(filter2) {
        filters.doFilter('filter3name', filter2).then(function (posts) {
            renderView(posts); 
        });
    });
    return filter1;
});

I basically want three methods to be called in sequence, with the output of each being piped to the next method. Is there anyway I can refactor this code to be more "sequence-like" - i.e. get rid of the nesting? I feel like there's something I'm missing with the when-framework here. I'm not doing it right, right?

Was it helpful?

Solution

Since doFilter returns a promise, we can do

filters.doFilter('filter1name', reqAndPosts)
    .then(function(filter1) {
        return filters.doFilter('filter2name', filter1);
    })
    .then(function(filter2) {
        return filters.doFilter('filter3name', filter2);
    })
    .then(renderView);

OTHER TIPS

There is another option to have both advantages of cleaner indentation and previous results available: using withThis.

filters.doFilter('filter1name', reqAndPosts).withThis({}).then(function(filter1) {
    this.filter1 = filter1; // since we used withThis, you use `this` to store values
    return filters.doFilter('filter2name', filter1);
}).then(function(filter2) {
    // use "this.filter1" if you want
    return filters.doFilter('filter3name', filter2);
}).then(renderView);

With a little thought you can write a generalised utility function that will take a start object and a filter sequence as its arguments, dynamically build the required .then chain, and return a promise of the multi-filtered result.

The function will look like this ...

function doFilters(filterArray, startObj) {
    return filterArray.reduce(function(promise, f) {
        return promise.then(function(result) {
            return filters.doFilter(f, result);
        });
    }, when(startObj));
}

... which is an adaptation of a pattern given here in the section headed "The Collection Kerfuffle".

For the operation you want, call as follows :

doFilters(['filter1name', 'filter2name', 'filter3name'], reqAndPosts).then(function(result) {
    //All filtering is complete.
    //Do awesome stuff with the result.
});

Provding it is not destroyed and is in scope, doFilters() will remain available to be used elsewhere in your code :

doFilters(['f1', 'f2', 'f3'], myOtherObject).then(function(result) {
    //...
});

With very little more effort, you could tidy things up by phrasing doFilters() as a method of filters. That would be best of all.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top