在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;内部链接在全局范围内运行。这会是个问题吗?只是模糊我需要做的事情。谢谢你的任何建议。
答案 0 :(得分:2)
所以你有一个重复的指令,它会减慢你的页面加载速度,因为在较低功率的设备上它会尝试进行大量的计算。
我认为,如果排队等待函数并按顺序完成它们,您会看到性能提升。
更高层次的想法:
代码,应该适合你:
// 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);
}
}
}
]);
这不是一个完整的解决方案,但应该让你走得很远。