javascript - AngularJS n:n许诺和数据同步/排序

标签 javascript angularjs

背景

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


从服务器获取/加载文章,
从文章中选择第一篇文章,然后
使用当前文章currentArticle从服务器获取相关图像。


问题

从服务器加载数据大约需要1秒钟返回商品记录,然后如上选择第一个商品,然后还从服务器返回相关的图像记录。问题在于,在该等待时间段内,第二个控制器(ImagesController)在第二个服务模块(ImageDataService)中查找缓存的数据,但找不到它,因为由于以下原因,第一个承诺显然未从Article Controller中解决:服务器延迟,因此ArticleController尚未缓存图像数据,这会炸毁随后的所有图像相关代码。如您在下面看到的,如果我尝试在$q.when(cachedImages)上返回cachedImages,它将返回一个承诺,但是该承诺永远不会解决。由于两个控制器都使用单独的$ q解析序列,这是有道理的,但是如果没有构建超级控制器,我不确定如何解决序列问题。

编辑

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


大多数教程或讨论都倾向于集中于1:1或1:n链接,这非常有效。没问题。
这是我遇到问题的n:n,即服务的ctrl,服务的服务和服务的n ctrl。我在n:n上可以找到的大多数内容都是基本的tut,它们加载了没有延迟问题的简单静态数组或对象。


尝试的方法


rootscope / watch:我已经在服务内部尝试了$rootscope.$watch()事件以及在控制器中进行了监视,即在ImageDataService内部的imageCached var上基于事件的方法,但是坦率地说,我发现这很麻烦,因为可能会产生不必要的开销,调试和测试问题,也就是说,它确实可以工作,但是当控制台记录一个深度嵌套的var时,我会不时看到很多迭代,这使事件方法看起来像黑盒子一样。


编辑-观看方法
示例:我可以将以下内容添加到第二个控制器ImageController或有效的ImageDataService中,就像$ 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();
             }

         }
     });



超时:我也试图将所有ImageController代码包装在超时中并也准备好文档,但是我发现这会进一步影响例如在我的Chart和Poll控制器中,我必须将指令包装在其他$ timeouts或$ intervals中,以针对ImagesController时间间隔进行调整,否则这些指令将无法正确加载DOM属性,因此,这会导致应用程序性能下降。
uber DataService服务或工厂数据解析:我试图解析uber DataServices服务提供程序中的所有数据,但是我发现所有控制器现在都遇到同样的问题,尽管uber服务解决了我现在需要与uber同步所需的排序问题和所有控制器。我知道异步...随时给我状态编程:)


问题与假设

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

是遵守承诺的最佳方法吗?如果是,是否有办法在多个控制器/服务之间实现承诺的同步或说更好的顺序解决?还是我会继续使用旋转仪监视和控制器作用域监视来拒绝事件方法?

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

请注意:

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>

最佳答案

使用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方法中。这将确保这些其他方法仅在从后端返回后才执行

关于javascript - AngularJS n:n许诺和数据同步/排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33723172/

相关文章:

javascript - 如何使用 AngularJS UI 路由器?

javascript - HTML5 本地存储不持久

javascript - 为什么 show() 只工作一瞬间?

JavaScript 幻灯片错误

javascript - Amcharts Angular Directive(指令)

javascript - Angular 获取全名

javascript - jQuery UI 不适用于动态创建的 DOM 元素?

javascript - React 路由器与 Meteor : How to remove code param from URL after redirect from OAuth without reload

javascript - 在 angularjs 中的非测试代码中使用 spy

javascript - 为什么我无法访问指令 html 中的 Controller 功能?