【问题标题】:How to load data synchronously in AngularJS application如何在 AngularJS 应用程序中同步加载数据
【发布时间】:2013-07-18 19:09:51
【问题描述】:

现在我知道,由于 javascript 的执行方式,建议您将所有远程请求作为异步而不是同步运行。虽然我同意 99% 的时间,但有时您确实希望将远程请求作为同步而不是异步运行。例如,加载会话数据是我想要同步执行的操作,因为我不希望在加载该数据之前呈现任何视图。这个 plunker 显示了异步加载会话数据的问题(注意:我使用 $timeout 来模拟异步调用会发生什么):

http://plnkr.co/edit/bzE1XP23MkE5YKWxRYrn?p=preview

data 属性不加载任何内容,因为在尝试获取数据时数据不可用,而 data2 加载只是因为在尝试获取数据时数据可用。现在在这种情况下,我可以将会话变量放在作用域上并完成它,但情况并非总是如此。

除了使用 jQuery 的 .ajax() 方法(尽量少依赖 jQuery)之外,有没有更好的方法在 Angular 应用程序中同步远程调用?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    如果您希望在加载控制器之前加载会话数据,则应将其作为resolve 参数包含(假设您使用的是$routeProvider)。

    例如:

    angular.module('mymodule', ['ngResource'])
    
      /* here's our session resource.  we can call Session.get() to retrieve it. */
      .factory('Session', ['$resource', function($resource) {
         return $resource('/api/session.json');
       }])
    
      /* here's our controller + route definition. */
      .config(['$routeProvider', function($routeProvider) {
    
        $routeProvider.when('/foo', {
          controller: 'MyCtrl',
          templateUrl: '/templates/foo.html',
    
          /* the controller will not be loaded until the items
           * below are all resolved! */
          resolve: {
            session: ['$q', 'Session', function($q, Session) {
              var d = $q.defer();
              Session.get(function(session) {
                /* session returned successfully */
                d.resolve(session);
              }, function(err) {
                /* session failed to load */
                d.reject(err);
              });
              return d.promise;
            }]
          }
        });
      }])
    
      .controller('MyCtrl', ['$scope', 'session', function($scope, session) {
        /* 'session' here is the key we passed to resolve above.
         * It will already be loaded and resolved before this function is called */
        $scope.session = session;
      }]);
    

    【讨论】:

    • 这个想法当时看起来很酷,但由于某种原因,变量在控制器中丢失了。有什么原因吗?
    • 我是否需要为所有路由定义提及解析?
    【解决方案2】:

    Angular 被硬编码以使请求异步。同步执行它需要其他代码,无论是自定义的还是来自其他库的。这是角度 1.0.7 的第 9269 行:

    xhr.open(method, url, true);
    

    第三个参数使它异步。

    我会退后一步,想想你是如何做事的。您可以在异步请求进行时提供一些加载指示器,并在成功回调中轻松控制视图的加载,以便在加载数据之前它不会出现。

    【讨论】:

      【解决方案3】:

      更好的解决方案是添加响应拦截器:

      checkAuth = ($q, $location) ->
        success = (response) ->
          response
        error = (response) ->
          errorCode = response.status
          $location.path '/login' if errorCode is 403 or errorCode is 401
          # $q.reject response - no need because we are redirecting before any other promises in the chain will resolve (were breaking our future promises)
      
        (promise) ->
          promise.then success, error
      
      $httpProvider.responseInterceptors.push checkAuth
      

      在你的 $routeProvider 中,或者在我的例子中是 $stateProvider:

      .state 'user',
        templateUrl: 'assets/views/user/partials/user.html'
        resolve:
          credentials: (checkLogIn) ->
            checkLogIn.get().$promise
      

      当 checkLogIn.get() 的 promise 被拒绝(错误处理程序被触发)时,假设它是 401 或 403 响应(未经身份验证或未经授权),promise 链将被破坏,用户将被“重定向”到/登录。

      使用此方法,任何错误调用都将被引导到拦截器中,而不是逐个路由处理错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-16
        • 2016-10-18
        • 1970-01-01
        • 2016-08-21
        • 1970-01-01
        • 2018-06-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多