Return 值而不是承诺 [停止嵌套的延迟承诺]

Return value instead of a promise [to stop nested deferred promise]

我有一堆嵌套的函数,因为顶级函数是 ajax 请求。 所以我想 return 一个值而不是嵌套 child 函数中的承诺。

Parent

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;
    }

Child 1

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

            //Some code here

            return data;
          })

    }

Child 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 return 一个值而不是 promise。

3 级的期望值

$rootScope.isAuthorized = checkAuthorize(toState);

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

是的,这种事情是可能的,但它会改变行为。您可能希望保留 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.

中的一次性 :: 表达式中使用它

残酷的事实是:你不能,除非你想要到处都是意大利面条式代码。

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

根据您希望在级别 3 中实现的目标,我猜测此函数将使用相同的输入被调用多次。在这种情况下,我要做的是在没有缓存结果的情况下调用 promise,并缓存结果。这样你就不必沿着承诺链走下去,尽管我在提供的代码中只计算了一个承诺。 resolve 上有多个处理程序,但只有一个 promise。

你可以为它使用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();

你可以运行你的代码就像使用nsynjs同步一样:它将逐步评估代码,如果某些函数returns承诺,它将暂停执行,等待promise resolve,将resolve result赋值给data 属性。因此,下面的代码将暂停在级别 1,直到 promise 被解析为实际值。

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>

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

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')
  }

});