当HighCharts渲染时,AngularJS ng-repeat会冻结浏览器

时间:2014-11-07 18:11:05

标签: angularjs highcharts rendering angularjs-ng-repeat

在ng-repeat中,我有一个使用$ http获取数据的指令,然后成功,初始化并呈现Highcharts。

html:

<div ng-repeat="item in items">
    <mychart datasource="item.id"></mychart>
</div>

js:

.directive('mychart', function($http){
    template: '<div>Loading chart...</div>',
    restrict: 'E',
    scope: {
        datasource : '='
    },
    link : function (scope, element, attrs) {
        $http(...).success( function (data) {

            var chartOptions = {
                chart : {
                    type: 'column',
                    renderTo: element[0]
                },
                xAxis : {
                    categories : data
                }
                ...
            };

            new Highcharts.Chart(chartOptions);  <!-- freezes browser?? -->

         });
    };
});

$ http是异步的,所以没有阻塞。但我相信调用Highcharts会导致浏览器冻结 有没有办法实现非阻塞渲染?在这里实施$ q是一种选择吗? $ evalAsync? 我想打电话给#34; new&#34;内部链接在全局范围内运行。这会是个问题吗?只是模糊我需要做的事情。谢谢你的任何建议。

1 个答案:

答案 0 :(得分:2)

所以你有一个重复的指令,它会减慢你的页面加载速度,因为在较低功率的设备上它会尝试进行大量的计算。

我认为,如果排队等待函数并按顺序完成它们,您会看到性能提升。

更高层次的想法:

design

代码,应该适合你:

// this service stores a request queue, allows adding requests to the queue and runs the function calls recursively. (This really queues up any functions you want to run sequentially, but relies on promises)

angular.module(Global.Application.name).service('queuedService', ['$q', '$http',
    function($q, $http)  {

        var arrayOfCalls = [];

        // this is what you add to the queue, what this does is wrap a function and 
        var functionWrapper = function(fn, context, params, onSuccess, onFailure){
            return function() {
                var deferred = $q.defer();
                var self = this;
                var a = fn.apply(context, params);
                a.then(function(response){
                     onSuccess.apply(self, [response]);
                     deferred.resolve(response);
                }, function(reason){
                    onFailure.apply(self, [reason]);
                    deferred .reject(reason);
                });

                return deferred.promise;
            };
        };

        function runArrayOfCalls(){
            alreadyRunning = true;
            if(arrayOfCalls.length > 0){
                    (arrayOfCalls.shift())().then(function(response){
                        console.log('succeeded - calls remaining', arrayOfCalls.length);
                        runArrayOfCalls();
                    }, function(){
                         console.log('failed - call remaining:', arrayOfCalls.length);
                        runArrayOfCalls();
                    });
            } else {
                alreadyRunning = false;
            }
        }

        // parametersObject could be an array or object passed, prefer object
        var addRequest= function(parametersObject, context, onSuccess, onFailure){
            // likely way to do this
            var config = {
                method: parametersObject.method, //"GET", "POST", etc 
                url: parametersObject.url, //"http://www.something.com", 
                headers: parametersObject.headers, //{"content-type": "application/json"}
            }
            if(parametersObject.data){
                if(config.method.toUpperCase() === "GET")
                    config.params = parametersObject.data; // get request
                else if(config.method.toUpperCase() === "POST")
                    config.data = parametersObject.data; // post request
            }

            var delayed = functionWrapper($http, context, parametersObject, onSuccess, onFailure);
            arrayOfCalls.push(delayed);

            runArrayOfCalls(); // auto run this array of calls
        };

        return {
            addRequestToQueue: function(parametersObject, context, onSuccess, onFailure){
                addRequest(parametersObject, context, onSuccess, onFailure);
            }, 
            fulfillNextRequest: function(){
                if(!alreadyRunning)
                    runArrayOfCalls();
            }
        };


    }
]);

假设您的指令是这样的,请注意这不是一个完整的指令,只是执行链接的部分

angular.module(Global.Application.name).directive('myDirective', ['queuedService',
    function(queuedService)  {

        return {
            link: function(scope, element, attrs){

                 var self = this; // this will be used for context of function wrapper
                 // take data in directive and add request
                 var parameters = {
                     url: 'something',
                     method: 'GET',
                     data: {
                         param1: "stuff"
                     }
                 }
                 var onSuccess = function(response){
                     console.log('response', response);
                     // draw chart here
                 };
                 var onFailure= function(reason){
                     console.log('failure');
                 };

                 queuedService.addRequestToQueue(parametersObject, self, onSuccess, onFailure);

            }
        }

    }
]);

这不是一个完整的解决方案,但应该让你走得很远。