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>=mappromise[ 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的初始化时间。

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值