AngularJS n:n承诺和数据同步/排序

时间:2015-11-15 18:13:53

标签: javascript angularjs

背景

随着我的应用程序的增长,我越来越努力使用AngularJS承诺跨多个控制器和服务进行同步/排序。在下面的示例中,我在初始加载过程中有一个文章控制器ArticleController和相关服务ArticleDataService

  1. 从服务器获取/加载文章
  2. 从文章和
  3. 中选择第一篇文章
  4. 使用当前文章currentArticle从服务器获取相关图像。
  5. 问题

    来自服务器的数据加载大约需要。 1秒返回文章记录,然后如上所述选择第一篇文章,然后还从服务器返回相关的图像记录。问题是在该延迟期间,第二个控制器(ImagesController)正在第二个服务模块(ImageDataService)中查找缓存数据,但无法找到它,因为第一个承诺显然没有从由于服务器延迟而导致文章控制器,因此ArticleController尚未缓存图像数据,这会使随后的图像相关代码爆炸。如下所示,如果我尝试在$q.when(cachedImages)上返回cachedImages,它将返回一个承诺,但该承诺永远不会被解决。由于两个控制器都使用单独的$ q解析序列,这是有道理的,但是如果没有构建超级控制器,我不确定如何修复排序问题。

    修改

    我正在尝试解决n:n链接/排序问题

    1. 大多数教程或讨论都倾向于关注1:1或1:n链接,它们完美无缺。没问题。

    2. 这是我遇到问题的n:n,即ctrl to service,service to service和n ctrl to service。我在n:n上找到的大部分内容都是加载简单静态数组或没有延迟问题的对象的基本内容。

    3. 经过尝试的方法

      1. rootscope / watch :我在服务中尝试了$rootscope.$watch()个事件以及在控制器中观察,即在ImageDataService内的imageCached var上基于事件的方法但坦率地说,我发现这很麻烦,因为可能会有不必要的开销,调试和测试问题。那说,它确实有效,但是当控制台记录深度嵌套的var时,我会看到很多迭代,这使得事件方法看起来像黑色boxish。
      2. 编辑 - 观看方法 示例:我可以将以下内容添加到第二个控制器ImageControllerImageDataService中,就像$ emit一样,然后杀死观察者,但正如我所说,这需要一些时间管理依赖方法,如图表数据指令。另外,我想知道混合承诺和事件是不好的做法还是JS中公认的最佳做法?

        var articleModelListener = $scope.$watch(function () {
                 return ImageDataService.getImages();
             },
             function (newValue, oldValue) {
                 if (newValue !== undefined && newValue !== null) {
                     if (Object.keys(newValue).length > 0) {
                        iCtrl.dataUrls = newValue;
                        // kill $watcher
                        articleModelListener();
                     }
        
                 }
             });
        
        1. 超时:我还试图将所有ImageController代码包装在超时中并且还准备好文档,但我发现这有进一步的影响,例如:在我的Chart和Poll控制器中,我必须在额外的$ timeouts或$ interval中包装指令以调整ImagesController时间间隔,否则指令将无法正确加载DOM属性,因此它会成为应用程序性能死亡链。
        2. uber DataService服务或工厂数据解析:我试图解析超级DataServices服务提供商中的所有数据,但我发现现在所有控制器都有同样的问题,因为尽管uber服务修复了我现在需要与uber和所有控制器进行同步。我知道异步...任何时候给我状态编程:)
        3. 问题& ASSUMPTION

          假设:超时和间隔包装是不良做法/反模式,因为它是瀑布?

          坚持承诺是最好的方法吗?如果是这样,有一种方法可以获得同步的承诺,或者更好地顺序解决多个控制器/服务 OR 我是否继续使用事件方法rotoscope手表和控制器范围手表?

          我的代码/问题示例如下:

          请注意:

          1。为了简洁起见,我删除了代码,即我没有测试过这个摘要代码,而是用它来举例说明上面的问题。

          2。所有和任何帮助非常感谢。对我滥用的任何术语表示道歉。

          HTML

          <section ng-controller="MainController as mCtrl"> 
              // removed HTML for brevity sakes
          </section>
          
          <section ng-controller="ImagesController as iCtrl"> 
              // removed HTML for brevity sakes
          </section>
          

          Angular JS(1.4。*)

          <pre><code>
              angular.module('articles', [
                  ])
          
                  .controller('ArticlesController', ['ArticleDataServices', 'ImageDataService', function(ArticleDataServices, ImageDataService) {
                      var mCtrl = this;
                      mCtrl.articles = {};
                      mCtrl.currentArticle = {};
                      mCtrl.images = {};
          
                      var loadArticles = function () {
                              return ArticleDataServices
                                  .getArticles()
                                  .then(function (articles) {
                                      if(articles.data) {
                                          mCtrl.articles = articles.data;
                                          return mCtrl.articles[Object.keys(mCtrl.articles)[0]];
                                      }
                                  });
                          },
                          loadCurrentArticleImages = function (currentArticle) {
                              return ImageDataService
                                  .getArticleImages(currentChannel)
                                  .then(function (imagesOfArticles) {
                                      if(imagesOfArticles.data) {
                                          return mCtrl.images = imagesOfArticles.data;
                                      }
                                  });
                          },
                          cacheImages = function (images) {
                              return ImageDataService
                                  .parseImages(images)
                                  .then(function () {
                                  });
                          };
          
                      loadChannels()
                          .then(loadArticles)
                          .then(loadCurrentArticleImages)
                          .then(cacheImages);
          
                  }])
              </code></pre>
          

          注意:它出现在下面的ImagesController,因为这个控制器正在第一个控制器之前执行它的方法,第一个控制器仍在等待来自服务器的数据,即cachedImages或承诺没有回来。

          <pre><code>
          .controller('ImagesController', ['ImageDataService', function(ImageDataService) {
              var iCtrl = this;
              mCtrl.images = {};
          
              var getCachedImageData = function () {
                  return ImageDataService
                      .getCachedImageData()
                      .then(function (images) {
                          if(images) {
                              return mCtrl.images = images;
                          }
                      });
              }
          }])
          
          .service('ArticleDataServices', ['$http',', $q', function($http, $q){
              var model = this,
                  URLS = {
                      ARTICLES: 'http://localhost:8888/articles'
                  },
                  config = {
                      params: {
                          'callback': 'JSON_CALLBACK',
                          'method': 'GET',
                          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                      }
                  };
          
              model.getArticles = function() {
                  config.params['url'] = URLS.ARTICLES;
                  return $http(config.params);
              };
          
              return {
                  getArticles: function () {
                      var deffered = $q.defer();
                      deffered.resolve(model.getArticles());
                      return deffered.promise;
                  }
              }
          }])
          
          .service('ImageDataService',['$http',', $q', function($http, $q){
              var model = this,
                  URLS = {
                      IMAGES: 'http://localhost:8888/images'
                  },
                  cachedImages,
                  config = {
                      params: {
                          'callback': 'JSON_CALLBACK',
                          'method': 'GET',
                          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                      }
                  };
          
              model.getArticleImages = function(currentArticle) {
                  config.params['url'] = URLS.IMAGES + '/' . currentArticle.slug;
                  return $http(config.params);
              };
          
              // Return images or $q.when 
              model.getCachedImageData = function() {
                  if (cachedImages) {
                      return cachedImages
                  } else {
                      return $q.when(cachedImages);
                  }
              };
          
              model.setImageCache = function(images) {
                  cachedImages = images;
              };
          
              return {
                  getArticleImages: function (currentArticle) {
                      var deffered = $q.defer();
                      deffered.resolve(model.getArticleImages(currentArticle));
                      return deffered.promise;
                  },
                  setImageCache:function (images) {
                      return model.setImageCache(images);
                  },
                  getCachedImageData:function () {
                      return getCachedImageData();
                  }
              };
          }]);
          
          </code></pre>
          

1 个答案:

答案 0 :(得分:1)

使用angular初始化时,您的问题很常见。正确的是您的服务中的退货承诺:

app.controller("AppController", function($scope, $ajax){
    $ajax.call("/people", "", "POST").then(function(req) {  
        $scope.people = req.data;
    });
});

app.factory("$ajax", function($http) {
    function ajax(url, param, method) {
        var requisicao = $http({
            method: method,
            url: url,
            data:param
        });

        var promise = requisicao.then(
            function(resposta) {
                return(resposta.data);
            }
        );
        return promise;
    }
    return({
        call:ajax
    });
});

请注意,该变量仅在返回服务时填充。重要的是你在Then方法中放置所有使用这种变量的方法或其他任何东西。这将确保这些其他方法仅在从后端返回后执行