Angular $ q then hell

In angular Q implementation, how can we make this kind of call better? In this case, loading d3 has nothing to do with loading data, it must be exactly parallel.

 d3Q.init()
    .then(function(d3) {
        scope.loadHistoryData()
            .then(function(data) {
                scope.renderHistoryGram(target, data, d3);
            });
    });

      

This smelly code is also difficult to test because there are several promises to be ridiculed. Any best practice for testing your code?

+3


source to share


2 answers


Since the second promise doesn't seem to depend on the first, you can run them in parallel and call the function after both have finished using $ q.all () .

$q.all({d3: d3Q.init(), data: scope.loadHistoryData()})
    .then(function(result) {
        scope.renderHistoryGram(target, result.d3, result.data);
    });

      



In the above case, we created an object so that we can use keys to reference the result of each of the promises. You can also pass an array from promises. In the case of an array (below), the result will be the result array in the same order as the promises.

$q.all([d3Q.init(), scope.loadHistoryData()])
    .then(function(result) {
        scope.renderHistoryGram(target, result[0], result[1]);
    });

      

+4


source


The easiest way without thinking too much about it:

d3Q.init()
    .then(function(d3) {
        return scope.loadHistoryData();
    }).then(function(data) {
        scope.renderHistoryGram(target, data, d3);
    });

      

Instead of acting on a promise within your handler, you return it to the "parent" context, if that makes sense.



Another way to do this is to write a scope handler to take d3

as an argument so that you can do this:

d3Q.init()
    .then(scope.loadHistoryData)
    .then(function(data) {
        scope.renderHistoryGram(target, data, d3);
    });

      

+1


source







All Articles