AngularJS ng-repeat 在 HighCharts 渲染时卡住浏览器

标签 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?? 我认为调用"new"内部链接在全局范围内运行。这会是一个问题吗?只是对我需要做的事情感到模糊。感谢您的任何建议。

最佳答案

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

我认为,如果您将函数调用排队并按顺序执行它们,您会看到性能改进。

更高层次的想法:

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);

            }
        }

    }
]);

这不是一个完整的解决方案,但应该可以帮助您走得更远。

关于AngularJS ng-repeat 在 HighCharts 渲染时卡住浏览器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26807437/

相关文章:

java - 如何绘制大型 BufferedImage 的一部分?

c++ - 完美的填充三角形渲染算法?

javascript - Vue : Rendered list show selected checkboxes

javascript - AngularJS 最佳实践 - 具有多种方法的工厂

javascript - Angular/Javascript 搜索对象键数组

javascript - AngularJS - 错误正文请求 POST

javascript - Highcharts 刻度位置未在多个 Y 轴上对齐

javascript - HighChart 类型 = 区域悬停颜色在多个点发生变化

javascript - 如何在angular js中进行路由?

javascript - HighCharts:使用 'split: true' 时,当值为零时隐藏工具提示