返回值而不是promise [停止嵌套延迟的promise]

时间:2017-06-21 12:59:50

标签: javascript angularjs es6-promise deferred

由于顶级功能而嵌套的一堆函数是一个ajax请求。 所以我想在嵌套子函数中返回值而不是promise。

let getUserPermissions = function(id) {
      let deferred = $q.defer();
      let promise = accessRequestService.getPermissions(id);
      promise.then(function(data) {
        deferred.resolve(data);
      }, function(err) {
        deferred.reject(err);
      })
      return deferred.promise;
    }

儿童1

$rootScope.userInit = function() {
        return getUserPermissions(vzid)
          .then(function(data) {

            //Some code here

            return data;
          })

    }

儿童2

let checkAuthorize = function(toState) {
  return $rootScope.userInit().then(
    function(data) {
//some code here 
      return data;
    });
}

等级3

checkAuthorize(toState).then( function(val){ 
 $rootScope.isAuthorized = val;
  if ($rootScope.isAuthorized == true) {
        $log.info('is Authorized')
      } else {
        $log.info('is not Authorized');
        throw new AuthorizationError()
      }
  })

在第3级,我们仍然在履行承诺。 child 2可以返回值而不是promise。

期望@ Level 3

$rootScope.isAuthorized = checkAuthorize(toState);

  if ($rootScope.isAuthorized == true) {
      $log.info('is Authorized')
      } else {
      $log.info('is not Authorized');
      throw new AuthorizationError()
     }

6 个答案:

答案 0 :(得分:6)

严峻的事实是:你不能,除非你想要意大利面条代码。

最好的解决方案是使用类似ui-router's resolve的内容,在向用户显示页面之前获取所需的所有权限。然后,您可以在控制器上使用它们而无需任何异步调用。

答案 1 :(得分:3)

您可以使用async/await构造。并使用Babel支持旧浏览器。

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  var x = await resolveAfter2Seconds(10);
  console.log(x); // 10
  console.log('done');
}

f1();

答案 2 :(得分:0)

是的,这类事情是可能的,但它会改变行为。您可能希望保留userInit,但您还要添加userInitValue变量并按如下方式对其进行初始化:

let userInitValue = null;
let userInit = function() {
    return getUserPermissions()
      .then(function(data) {
        userInitValue = data;
        return data;
      })
}

所以现在userInitValue将从null开始,然后再初始化为相关数据。

function isKnownAuthorized(toDoSomething) {
    // If we don't know whether the user is authorized
    //   because we are still waiting for the server to tell us
    //   then return false and disallow access for now
    if(!userInitValue) return false;

    // Otherwise return the truth
    //   (as of when we got the server response)
    return userInitValue.isAuthorized(toDoSomething);
}

再次注意行为的变化。获得即时响应的价格(可能在服务器提供数据之前)是即时响应可能是错误的。所以不要在AngularJs中的一次性表达式中使用它。

答案 3 :(得分:0)

基于你希望在Level 3中实现的目标,我猜这个函数将使用相同的输入多次调用。在这种情况下,如果没有缓存结果,我会做的是调用promise,并缓存结果。这样您就不必沿着承诺链走下去,尽管我只计算所提供代码中的一个承诺。解决了多个处理程序,但只有一个承诺。

答案 4 :(得分:0)

您可以使用nsynjs运行您的代码,就好像它是同步的一样:它将逐步评估代码,如果某个函数返回promise,它将暂停执行,等待promise被解析,并分配将结果解析为data属性。因此,下面的代码将在第1级暂停,直到承诺被解析为实际值。

var getUserPermissions = function(id) {
    return new Promise(function(resolve, reject) {
        setTimeout(function(){
        resolve({
                id: id,
                isAdmin: "yes he is",
            })
        }, 1000);
    });
};

function synchronousCode() {
    console.log("start");
    var vzid = 35;
    var userInit = function() {
        return getUserPermissions(vzid).data;
    };
    var checkAuthorize = function() {
	    return userInit().isAdmin;
    };
    var isAuthorized = checkAuthorize();
    console.log(isAuthorized);
};
	
nsynjs.run(synchronousCode, null, function(){
	console.log("finish");
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

答案 5 :(得分:0)

我正在使用$ state.transitionTo方法在$stateChangeStart之前调用。

var transitionTo = $state.transitionTo;
$state.transitionTo = function(to, toParams, options) {
  var from = $state.$current,
    fromParams = $state.params;

  to = to.name ? to : $state.get(to);

    $rootScope.state = {
      to: to.self,
      toParams: toParams,
      from: from.self,
      fromParams: fromParams,
      options: options
    }

  if (options.notify && options.notify !== false) {
    return $q.reject(new AuthorizationError('Rejecting $state.transitionTo', 'Transition Rejected'));
  } else {
    return checkAuthorize(to).then(function(auth) {
      $rootScope.isAuthorized = auth;
        return transitionTo(to, toParams, options)
    })
  }
}

<强> StateChangeStart

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
  $log.info("Route change start from", fromState.url, "to", toState.url);
  //event.preventDefault();

  if ($rootScope.isAuthorized == true) {
    $log.info('is Authorized')
    //$state.go($rootScope.toState.name);
  } else {
    event.preventDefault();
    $log.info('is not Authorized');
    throw new AuthorizationError('User is not Authorized.', 'NOT_AUTHENTICATED')
  }

});