Angularjs call asynchronous before page renders

前端之家收集整理的这篇文章主要介绍了Angularjs call asynchronous before page renders前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

仅记录下最近学到的一点angular js 知识。

业务描述

前情说明

最近在做一个angularjs的相关项目,需要在page render之前调用后台的restapi 获取用户名user,用该值去设置某些service并用于前端页面渲染(全部页面渲染之前必须得到user),并且在app.run 中要inject的一些service(例如项目中item.js定义的Item service) 也需要获取到user。

解决方

要点1 - promises

promises在angularjs中是通过$q来提供的。
REST API 调用封装在Data service中,Data service 是基于\$http的,因此是hardcode了异步的调用
service定义如下:

angular.module('myApp')
  .config(function($httpProvider){
    $httpProvider.defaults.headers.common['Content-Type'] = 'application/json;charset=utf-8';
  })
  .service('Data',function ($q,$http) {
         this.getUser() = function(){
           return getUrl('xxxx');
         };
         //define getUrl method
         var getUrl = function(url,timeout) {
           var defferred = $q().defer;
           var opts = {
             method:'GET',url:url
           };
           if(timeout)
              opts.timeout = timeout;
           $http(opts)
              .success(function(result,status,headers){
                //do some handling
                deferred.resolve(result);
              })
              .error(function(error){
              // do some error handling
                  deferred.reject(xxx);
              });
              return deferred.promise;
         };//end of getUrl

  });//end of service 

为了获取a,定义了一个单独的service User in user.js.

angular.module('myApp')
    .service('User',function(Data,$rootScope,otherService) {

        //this is the default locale.
        var DEFAULT_VALUE = 'Guest';

    this.getUser = function () {
        var promise = Data.getUser().then(
            function(result){ // fetch succeed 
                $rootScope.user = result;
            },function(result){ //fetch Failed.
                $rootScope.user = DEFAULT_VALUE ;
            }
        ).finally(
            function(){
             otherService.setxxxx($routScope.user);//if need to set.
            }
        );
    };
});

要点2 - resolve of $routeProvider

promise 解决获取到值后的回调问题,仍需要其他方法来保证在页面加载前能够完成回调函数的执行。
从各处资料中找到了两种思路:
1) manual bootstrap angular app
2 ) $routeProvider中 set resolve
由于手动bootstrap app受组内原因限制被否,因此最终选择了第二个思路。

resolve定义

routeProviderresolveObject.<string,function>=map@H_250_502@promise[ routeProvider](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider) 所说,router 会等到里面所有的promise 对象都 成功resolve,才会初始化控制器。 这正是我所需要滴!

global resolve

但是因为router 配置的比较多,每个router都要设置相同的resolve,会比较麻烦,所以通过修改$routeProvider的 when函数定义,来达到简化代码的目的。

angular
  .module('myApp',[
    'ngRoute'
    //....etc
  ])
  .config(function ($routeProvider) {
  // can't add service in the argument since config only support provider

    //define universal resolve for all routes
    var globalResolve = {
      'user' : function(User){ // User service as argument
          return User.getUser();
      }
    };
   // extend routeProvider to have a global resolve
    var originWhen = $routeProvider.when;

    $routeProvider.when = function(path,route){
      route.resolve = route.resolve || (route.resolve = {});
      angular.extend(route.resolve,globalResolve);  
      return originWhen.call($routeProvider,path,route);
    };


    $routeProvider
      .when('/',{
        templateUrl: 'views/main.html',controller: 'MainCtrl'
      })
      //....etc routers
});

要点3 app.run 和 resolve的 promise回调执行顺序

在项目中有以下定义:

app.run(function (\$rootScope,\$location,Data,Time,\$timeout,Item) {
//do something
});

其中Item service的定义中用到了 user值,因此会出现问题。
不过此处还需要更深的对angularjs service初始化顺序、app.run执行时间、resolve完成时间三者顺序的调研,但是根据此次的观察,app.run 执行可能是在user的值被获取并完成回调处理之前。
目前也没有找到很好的办法来解决这个问题,所幸app.run 要注入的service 只有Item 是依赖user 并且可以从app.run中移走到其他controller里面的,因此最终就是从app.run的注入service列表中移走了Item,推迟了Item的初始化时间。

有更好的方法的话,希望可以留言教一下我咯~

猜你在找的Angularjs相关文章