blaster
blaster

Reputation: 8937

AngularJS - Computation-Heavy Tasks

Is there a pattern in Angular apps for computation-heavy tasks? (Beyond just using $timeout with a delay of 0 to let them get off the call stack?) Even using $timeout seems to make the UI unresponsive when the processing itself kicks in. Do I need to be looking at Web Workers or something like that, or is there an "Angular way?"

Upvotes: 3

Views: 3067

Answers (2)

blaster
blaster

Reputation: 8937

I came up with a way to solve my UI responsiveness problem by creating special loop functions that use an Angular $timeout each time through the loop.

app.service('responsivenessService', function($q, $timeout) {
    var self = this;

    // Works like Underscore's map() except it uses setTimeout between each loop iteration
    // to try to keep the UI as responsive as possible
    self.responsiveMap = function(collection, evalFn)
    {
        var deferred = $q.defer();

        // Closures to track the resulting collection as it's built and the iteration index
        var resultCollection = [], index = 0;

        function enQueueNext() {
            $timeout(function () {
                // Process the element at "index"
                resultCollection.push(evalFn(collection[index]));

                index++;
                if (index < collection.length)
                    enQueueNext();
                else
                {
                    // We're done; resolve the promise
                    deferred.resolve(resultCollection);
                }
            }, 0);
        }

        // Start off the process
        enQueueNext();

        return deferred.promise;
     }
     return self;
});

This mapping function returns a promise which can be assignable to a $scope. Usage is similar to the map() functions from Underscore or native Javascript arrays in newer browsers:

$scope.results = responsivenessService.responsiveMap(initialdata, function() {
    // Long-running or computationally intense code here
    return result;
});

Code that would originally have blocked the whole UI now appears to run in the background (although essentially it's an illusion, like calling Application.DoEvents periodically in older applications). Nice and generic, as long as the long-running code is conducive to a looping map()-style operation!

Upvotes: 2

nekaab
nekaab

Reputation: 442

Because JavaScript is single threaded, you need to either do the computations server-side, or do the timeouts in between the processing (See underscore's defer(), http://underscorejs.org/#defer). Otherwise, the UI will inevitably get blocked.

Upvotes: 2

Related Questions