【问题标题】:Resolve promise in service without callback in controller解决服务中的承诺而无需在控制器中回调
【发布时间】:2015-06-17 14:03:20
【问题描述】:

我想问/讨论这是好的还是坏的做法 - 在控制器中进行服务调用的优点和缺点是什么?尽可能干净和简短。换句话说:不再有回调,而是利用 Angular 的 Angular 绑定原则。

看看我 fork 的 Plnkr: http://plnkr.co/edit/zNwy8tNKG6DxAzBAclKY

我想实现 Plnkr 第 42 行注释掉的内容 > $scope.data = DataService.getData(3);

app.factory('DataService', function($q, $http) {
      var cache = {};
      var service= {
        data:{src:''},
        getData: function(id, callback) {
          var deffered = $q.defer();
          if (cache[id]) {
            service.data.src = 'cache';
            deffered.resolve(cache[id])
          } else {
            $http.get('data.json').then(function(res) {
              service.data.src = 'ajax';
              cache[id] = res.data;
              cache[id].dataSource = service.data.src;
              deffered.resolve(cache[id])
            })
          }
          return deffered.promise.then(callback);
        }
      }
      return service
    })
     app.controller('MainCtrl', function($scope, DataService) {

        DataService.getData(3, function(result) {
          $scope.data = result;
        });

     //$scope.data = DataService.getData(3);
});

【问题讨论】:

    标签: angularjs callback controller promise angular-promise


    【解决方案1】:

    关于请求数据和返回承诺的服务,我的最佳做法是:

    • 返回一个承诺(在 DataService 中,返回 deferred.promise)
    • 在控制器中,调用DataService.getData(3).then(, )

    所以我不会将回调传递给使用承诺的服务函数。

    更难的问题是服务功能应该做什么,then(function(data) {...})应该做什么。以下是一些指导方针:

    • 任何共享的东西(数据/重复功能),在服务中实现
    • 与将数据/功能绑定到 UI 元素相关的任何内容,在控制器中实现
    • 让您的控制器尽可能简单 - 它们应该只是在 UI 元素和模型之间建立链接。
    • 任何模型逻辑、处理、格式解析等 - 在服务中实现

    我在阅读了cmets后添加了这部分:

    如果您需要进行一些处理(例如检查缓存的结果、解析结果等),那么执行此操作的正确位置是在服务中。

    所以我会修改你的代码如下:

    var service= {
      data:{src:''},
      getData: function(id) {
        var deffered = $q.defer();
        if (cache[id]) {
          service.data.src = 'cache';
          deffered.resolve(cache[id]);
          return deferred;
        } else {
          return $http.get('data.json').then(function(res) {
            service.data.src = 'ajax';
            cache[id] = res.data;
            cache[id].dataSource = service.data.src;
            return cache[id]; // this will resolve to the next ".then(..)"
          });
        }
      }
    }
    

    【讨论】:

    • 您希望在控制器中实现的另一件事是处理 DataService 的错误。通常你会想告诉用户错误(== 链接数据到 ui 元素),这应该在控制器中完成。所以这是一个赞成返回承诺(而不是传递回调)的专业人士。
    • 会接受这个遮阳篷作为引导我走向正确方向的那个。一些关于 UI 操作的个人反馈:不希望在控制器中这样做,这些东西需要由指令处理(尽可能)。
    • 还有一个问题,那就是关于链接承诺,我宁愿看到这在服务中完成,然后在控制器变得一团糟之前。你对此有何看法?
    • 我同意 - 如果您要对 $http 响应进行一些处理,然后在服务中处理它,然后确保您返回结果(它将解析为下一个链式承诺)。还要确保处理错误,以便将它们传递给下一个承诺处理程序。
    【解决方案2】:

    AfaIk 这是不可能的 - 看到这个Thread

    您可以使用 angular-route 来“自动”解决承诺。已解决的 Promise 将被注入到您的控制器中。

    【讨论】:

    • 好一个,我喜欢(干净的)解决方案,但是这是一项可以在运行时调用的服务,而不是在初始构建视图时调用。不过好点。
    • 角度路由状态在配置生命周期中定义,但承诺将在运行时解决
    • 我的意思是在单击按钮时调用服务,例如从 UI 中。角度路线对我没有帮助吗?
    【解决方案3】:

    你可以这样做plunker

    <!DOCTYPE html>
    <html ng-app="plunker">
    
    <head>
      <meta charset="utf-8" />
      <title>AngularJS Plunker</title>
      <script>
        document.write('<base href="' + document.location + '" />');
      </script>
      <link href="style.css" rel="stylesheet" />
      <script data-semver="1.2.4" src="http://code.angularjs.org/1.2.4/angular.js" data-require="angular.js@1.2.x"></script>
      <script src="app.js"></script>
      <script>
        app.factory('DataService', function($q, $http) {
          var cache = {};
          var service= {
            data:{src:''},
            getData: function(id, callback) {
              var deffered = $q.defer();
              if (cache[id]) {
                service.data.src = 'cache';
                deffered.resolve(cache[id])
              } else {
                $http.get('data.json').then(function(res) {
                  service.data.src = 'ajax';
                  cache[id] = res.data;
                  cache[id].dataSource = service.data.src;
                  deffered.resolve(cache[id])
                })
              }
              return deffered.promise;
            }
          }
          return service
        })
         app.controller('MainCtrl', function($scope, DataService) {
    
             DataService.getData(3).then(function (data) {
              $scope.data = data;
            });
        });
      </script>
    </head>
    
    <body ng-controller="MainCtrl">
    
    <div>Source: {{data.dataSource}}</div>
      <pre>{{data}}</pre>
    </body>
    
    </html>
    

    【讨论】:

    • 这是我分叉的原始 plnkr,根据我的描述,这正是我不想要的。
    猜你喜欢
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多