由于我们的服务器无法对JSON数据进行分页,因此我希望流式传输JSON并将其逐页添加到控制器的模型中.用户不必等待整个流加载,因此我刷新每个X(页面大小)记录的视图.
我发现oboe.js用于解析JSON流并使用bower将其添加到我的项目中. (凉亭安装双簧管 – 保存).
我想在流式传输期间更新控制器模型.我没有使用$q实现的pomises,因为只有一个.resolve(…)可能,我希望通过流加载多页数据,因此需要在每个页面调用$digest.调用的restful服务是/ service / tasks / search
'use strict'; angular.module('myStreamingApp') .factory('Stream',function() { return { search: function(schema,scope) { var loaded = 0; var pagesize = 100; // JSON streaming parser oboe.js oboe({ url: '/service/' + schema + '/search' }) // process every node which has a schema .node('{schema}',function(rec) { // push the record to the model data scope.data.push(rec); loaded++; // if there is another page received then refresh the view if (loaded % pagesize === 0) { scope.$digest(); } }) .fail(function(err) { console.log('streaming error' + err.thrown ? (err.thrown.message):''); }) .done(function() { scope.$digest(); }); } }; });
我的控制器:
'use strict'; angular.module('myStreamingApp') .controller('MyCtrl',function($scope,Stream) { $scope.data = []; Stream.search('tasks',$scope); });
这一切都有效.一段时间后,系统变慢,刷新浏览器后http调用不会终止.当加载的记录太多时,浏览器(chrome)也会崩溃.
也许我在错误的轨道上,因为将范围传递给工厂搜索功能并没有“感觉”正确,我怀疑在该范围内调用$digest会给我带来麻烦.欢迎提出有关此主题的任何想法.特别是如果您有实现它的想法,工厂(或服务)可以返回承诺,我可以使用
$scope.data = Stream.search('tasks');
在控制器中.
工厂(名为Stream)有一个搜索功能,它传递Ajax请求的参数和回调函数.正在为流加载的每个数据页调用回调.回调函数通过deferred.promise调用,因此范围可以自动更新每个页面.为了访问搜索功能,我使用一个服务(名为Search),该服务最初返回一个空的数据.随着流的进行,工厂调用服务传递的回调函数,并将页面添加到数据中.
我现在可以在控制器中调用搜索服务表单,并将返回值分配给作用域数据数组.
服务和工厂:
'use strict'; angular.module('myStreamingApp') .service('Search',function(Stream) { return function(params) { // initialize the data var data = []; // add the data page by page using a stream Stream.search(params,function(page) { // a page of records is received. // add each record to the data _.each(page,function(record) { data.push(record); }); }); return data; }; }) .factory('Stream',function($q) { return { // the search function calls the oboe module to get the JSON data in a stream search: function(params,callback) { // the defer will be resolved immediately var defer = $q.defer(); var promise = defer.promise; // counter for the received records var counter = 0; // I use an arbitrary page size. var pagesize = 100; // initialize the page of records var page = []; // call the oboe unction to start the stream oboe({ url: '/api/' + params.schema + '/search',method: 'GET' }) // once the stream starts we can resolve the defer. .start(function() { defer.resolve(); }) // for every node containing an _id .node('{_id}',function(node) { // we push the node to the page page.push(node); counter++; // if the pagesize is reached return the page using the promise if (counter % pagesize === 0) { promise.then(callback(page)); // initialize the page page = []; } }) .done(function() { // when the stream is done make surethe last page of nodes is returned promise.then(callback(page)); }); return promise; } }; });
现在我可以在控制器内调用服务,并将服务的响应分配给范围:
$scope.mydata = Search({schema: 'tasks'});
2014年8月30日更新
我已经创建了一个angular-oboe模块,上面的解决方案有点结构化.
https://github.com/RonB/angular-oboe