什么是正确的角度模式,用于从单个服务调用返回多个*独立*异步结果

时间:2014-06-02 23:06:23

标签: javascript angularjs asynchronous service

我正在研究搜索界面。有一个结果列表视图,每个结果可以“扩展”以显示更多数据。当用户展开结果时,我异步获取可包含0到12张图片的详细信息。这是通过“细节服务”完成的,这是一种角度感的服务。

现在,因为我的目标是“本地化的感觉”并且这些图片可能很重要,所以我不希望它们在完成加载之前出现。

问题是:当每个图像加载时,服务如何通知其客户端(控制器)?

许多文章都建议将promises作为最佳方式。天真地,我会想要返回一个承诺数组 - 每个图像一个 - 将在图像加载后解析。

这似乎是一个严厉的解决方案,需要一个循环将then()函数附加到任意数量的promise。

另一种流行的解决方案是在$ rootScope上使用broadcast()。这看起来“草率”,因为我知道正好谁正在“倾听”结果。

“承诺数组”是正确的,还是更简洁或“有角度”的方式?

注意:这些是独立的结果,不应链接或组成一个承诺。

编辑:为不明确的问题道歉。所需的功能是每张图片在加载时显示。所以聚合承诺是不受欢迎的。这让核心问及承诺是否是最简洁的解决方案。我发现了我认为更好的一个,在答案中表示为延迟显示直到图像加载的图像指令。将此逻辑移出服务并转换为指令似乎是一种更优雅的解决方案。

4 个答案:

答案 0 :(得分:1)

我会说承诺的一系列承诺'是正确的方法。

您可以使用.all()方法,该方法将任意数量的promise作为参数(作为数组)。然后,您可以将此承诺解决为单一承诺。

  

返回将使用值的数组/散列解析的单个promise,每个值对应于promises数组/散列中相同索引/键的promise。如果任何承诺通过拒绝得到解决,则此结果承诺将被拒绝并具有相同的拒绝价值。

    $q.all([firstPromise.then(function(){
                             //do something
                             }),
            secondPromise.then(function(){
                             //do something else
                               })
           ])
     .then(function(){
            //do something after all promises are resolved
            });

https://docs.angularjs.org/api/ng/service/ $ Q

答案 1 :(得分:0)

promises数组中的每个promise都是并行和异步执行的。 $ q.all让你处理它们都成功解决。

答案 2 :(得分:0)

使用几种方法后,似乎将图像加载检查移动到指令会产生最简洁,可重用和可读的解决方案。

// directive for an "optional background image" element that will only display if and
// after the image loads
.directive('optBgImg',
    function() {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                // create an image object to get a reliable onload event
                // (using load on the element unreliable for dynamic divs)
                var img = new Image();
                // onload handler (on the image, not the element) 
                img.onload = function() {
                    img.onload = null;
                    // add a class to reveal the image
                    element.addClass("loaded");
                    // set the background image on the element
                    // (using background image for advanced formatting)
                    element.css("background-image", "url(" +
                                    attrs.optBgImg + ")");
                };
                img.onerror = function() {
                    img.onerror = null;
                    // could remove the element here for extra credit
                };
                // set the source for the image to initiate the load
                img.src = attrs.optBgImg;
            }
        };
    });

答案 3 :(得分:0)

你可以写这样的东西(在这个例子中只有$ http.get服务):

 var getAllServicesResult = function (servicesList) {  

        var promises = [];

        angular.forEach(servicesList, function (s, index) {

            var deffered = $q.defer();
            $http.get(s.path, { params: s.params }).success(function (response) {
                deffered.resolve(response);
            }).error(function (error) {
                deffered.reject();
            });

            promises.push(deffered.promise);
        });

        return $q.all(promises);
    }

servicesList是这样的数组:

servicesList =[{path: '/Reference/GetRefrenceByType'
             , params: { refType: d.Service_Ref_Field_Name, baseMapType: 0 }}
             ,{},...];