我有一个在 SharePoint 2013 页面上运行的 Angular SPA。在代码中,我使用 $q 从使用 REST 的 10 个不同 SharePoint 列表中提取数据,然后将它们合并到一个 JSON 对象中以在网格中使用。代码运行并输出预期的合并数据,但它会泄漏并在一段时间后使浏览器崩溃。
这是服务中的代码:
factory.getGridInfo = function() {
var deferred = $q.defer();
var list_1a = CRUDFactory.getListItems("ListA", "column1,column2,column3");
var list_1b = CRUDFactory.getListItems("ListB", "column1,column2,column3");
var list_2a = CRUDFactory.getListItems("ListC", "column4");
var list_2b = CRUDFactory.getListItems("ListD", "column4");
var list_3a = CRUDFactory.getListItems("ListE", "column5");
var list_3b = CRUDFactory.getListItems("ListF", "column5");
var list_4a = CRUDFactory.getListItems("ListG", "column6");
var list_4b = CRUDFactory.getListItems("ListH", "column6");
var list_5a = CRUDFactory.getListItems("ListI", "column7");
var list_5b = CRUDFactory.getListItems("ListJ", "column7");
$q.all([list_1a, list_1b, list_2a, list_2b, list_3a, list_3b, list_4a, list_4b, list_5a, list_5b])
.then(function(results){
var results_1a = results[0].data.d.results;
var results_1b = results[1].data.d.results;
var results_2a = results[2].data.d.results;
var results_2b = results[3].data.d.results;
var results_3a = results[4].data.d.results;
var results_3b = results[5].data.d.results;
var results_4a = results[6].data.d.results;
var results_4b = results[7].data.d.results;
var results_5a = results[8].data.d.results;
var results_5b = results[9].data.d.results;
var combined_1 = results_1a.concat(results_1b);
var combined_2 = results_2a.concat(results_2b);
var combined_3 = results_3a.concat(results_3b);
var combined_4 = results_4a.concat(results_4b);
var combined_5 = results_5a.concat(results_5b);
for(var i = 0; i < combined_1.length; i++){
var currObj = combined_1[i];
currObj["column4"] = combined_2[i].column4;
currObj["column5"] = combined_3[i].column5;
currObj["column6"] = combined_4[i].column6;
currObj["column7"] = combined_5[i].column7;
factory.newObjectArray[i] = currObj;
}
deferred.resolve(factory.newObjectArray);
},
function (error) {
deferred.reject(error);
});
return deferred.promise;
};
这是 CRUDFactory 中的 REST 调用:
factory.getListItems = function (listName, columns){
var webUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('"+listName+"')/items?$select="+columns+"&$top=5000";
var options = {
headers: { "Accept": "application/json; odata=verbose" },
method: 'GET',
url: webUrl
};
return $http(options);
};
然后这里是 Controller 位:
$scope.refreshGridData = function(){
$scope.hideLoadingGif = false;
$scope.GridData = "";
GlobalFactory.getGridInfo()
.then(function(){
$scope.GridData = GlobalFactory.newObjectArray;
$scope.hideLoadingGif = true;
});
};
更新 1:每个请求,这是 HTML(只是一个我们使用 angular-ui-grid 的简单 div)
<div ui-grid="GridOptions" class="grid" ui-grid-selection ui-grid-exporter ui-grid-save-state></div>
此代码首先声明一些 get 调用,然后使用 $q.all 迭代调用并获取数据。然后它存储结果并将它们合并到总共 5 个数组。然后,因为我的列表结构是正确的和静态的,所以我能够遍历合并的数组之一,并将其他数组中的数据提取到我分配给 factory.newObjectArray 的一个主数组中,我声明为我的服务中的一个全局变量并用作我的网格数据源。
代码运行并且不会引发任何错误,但问题出在(我相信)“getGridInfo”函数上。如果我不注释掉任何 REST 调用,浏览器将使用 45 MB 的数据,这些数据不会被 GC 获取,然后每次点击都会进行复合,直到 session 结束或崩溃。如果我注释掉除一个之外的所有调用,我的页面只使用 18.4 MB 的内存,这很高但我可以忍受。
那么有什么关系呢?我需要在某处销毁某些东西吗?如果是这样,是什么以及如何?还是这与我正在使用的 REST 功能有关?
更新 2:网格使用的返回结果(factory.newObjectArray)总共包含 5,450 个项目,每个项目在合并后大约有 80 个属性。上面的代码经过简化,显示了每个列表拉动几列,但实际上,我每个列表拉动 5-10 列。
最佳答案
在一天结束时,您要处理大量数据,因此内存问题可能始终是一个问题,您可能应该考虑是否需要将所有数据都保存在内存中。
您可能应该尝试实现的主要目标是限制数组的重复,并尽量减少内存占用,并在完成处理后尽快释放内存。
请考虑以下事项。您提到返回的实际列数比您的示例多,因此我已将其考虑在内。
factory.getGridInfo = function () {
var deferred = $q.defer(),
// list definitions
lists = [
{ name: 'ListA', columns: ['column1', 'column2', 'column3'] },
{ name: 'ListB', columns: ['column1', 'column2', 'column3'], combineWith: 'ListA' },
{ name: 'ListC', columns: ['column4'] },
{ name: 'ListD', columns: ['column4'], combineWith: 'ListC' },
{ name: 'ListE', columns: ['column5'] },
{ name: 'ListF', columns: ['column5'], combineWith: 'ListE' },
{ name: 'ListG', columns: ['column6'] },
{ name: 'ListH', columns: ['column6'], combineWith: 'ListG' },
{ name: 'ListI', columns: ['column7'] },
{ name: 'ListJ', columns: ['column7'], combineWith: 'ListI' },
],
// Combines two arrays without creating a new array, mindful of lenth limitations
combineArrays = function (a, b) {
var len = b.length;
for (var i = 0; i < len; i = i + 5000) {
a.unshift.apply(a, b.slice(i, i + 5000));
}
};
$q.all(lists.map(function (list) { return CRUDFactory.getListItems(list.name, list.columns.join()); }))
.then(function (results) {
var listResultMap = {}, var baseList = 'ListA';
// map our results to our list names
for(var i = 0; i < results.length; i++) {
listResultMap[lists[i].name] = results[i].data.d.results;
}
// loop around our lists
for(var i = 0; i < lists.length; i++) {
var listName = lists[i].name, combineWith = lists[i].combineWith;
if(combineWith) {
combineArrays(listResultMap[combineWith], listResultMap[listName]);
delete listResultMap[listName];
}
}
// build result
factory.newObjectArray = listResultMap[baseList].map(function(item) {
for(var i = 0; i < lists.length; i++) {
if(list.name !== baseList) {
for(var c = 0; c < lists[i].columns.length; c++) {
var columnName = lists[i].columns[c];
item[columnName] = listResultMap[list.name][columnName];
}
}
}
return item;
});
// clean up our remaining results
for (var i = 0; i < results.length; i++) {
delete results[i].data.d.results;
delete results[i];
}
deferred.resolve(factory.newObjectArray);
},
function (error) {
deferred.reject(error);
});
return deferred.promise;
};
关于arrays - 如何更有效地在 Angular 应用程序中合并 REST 调用结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33355870/