2014-08-29 54 views
7

我对Angular来说很新,所以也许我在问不可能,但无论如何,这是我的挑战。在AngularJS中使用oboe.js流式传输JSON的解决方案?

由于我们的服务器无法对JSON数据进行分页,因此我想将JSON流式传输并将其逐页添加到控制器的模型中。用户不必等待整个流加载,因此我刷新每个X(pagesize)记录的视图。

我发现了解析JSON流的oboe.js并将它添加到我的项目使用鲍尔。 (凉亭安装双簧管 - 保存)。

我想在流式传输过程中更新控制器型号。我没有使用pomises的$ q实现,因为只有一个.resolve(...)可能,并且我想要通过流加载多页数据,因此需要在每个页面中调用$ digest。这就是所谓的RESTful服务是/服务/任务/搜索

我创建了一个工厂,一个搜索功能,我从控制器内调用:

'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)也会崩溃。 也许我在错误的轨道上,因为将范围传递给工厂搜索功能并不“感觉”正确,我怀疑在该范围调用$摘要给我带来麻烦。任何关于这个问题的想法都是受欢迎特别是如果你有一个关于在工厂(或服务)可能返回承诺的地方实施它的想法,并且我可以在控制器中使用

$scope.data = Stream.search('tasks'); 

回答

14

我进一步挖掘并提出了以下解决方案。它可以帮助某人:

工厂(名为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