在 Promise 之外获取变量值

Get variable value outside of Promise

我在 AngularJs 中有一项服务,它将 return 来自数据库的值。

userData.getUserData(function(response) {
  $scope.uid = response
});

当我在控制器中注入此服务时,它将 return 一个 Promise, 但是我在我的功能之外需要这个 Promise 值,我该怎么做?

Plunkr link of code

您所讨论的问题与以下事实有关:您在承诺 return 之前尝试使用 $scope.uid

你可以通过几个步骤来解决这样的问题,主要是你可以在使用之前初始化作用域变量。例如,如果 response 是一个对象,你可以这样做:

$scope.uid = {};

userData.getUserData(function(response) {
  $scope.uid = response;
});

那么你的 var 就不会是未定义的。但是你也应该考虑你何时以及如何使用这个变量,无论你是否想要这样初始化都会影响。

如果你这样登录,它会起作用

userData.getUserData(function(response) {
  $scope.uid = response;
  console.log($scope.uid);
});

如果你这样记录,它将不会工作,因为这个日志不会等待你承诺return,然后再记录;

userData.getUserData(function(response) {
  $scope.uid = response;
});

console.log($scope.uid);

您需要提供更多信息以确定如何最好地处理使用此 returned 信息和局部变量。但是这个问题的总体思路是您试图在承诺返回之前记录变量。

TL:DR 你可以在函数外访问$scope.uid,你需要等待响应给它数据在它进入内部之前,如果您不希望它开始时可以初始化它 undefined

UPDATE:您需要使用回调来触发第二个调用在您收到第一个回调之后

 userData.getUserData(function(response) {
  $scope.postRequest(response);
 });
 $scope.postRequest = function(val) {
    $firebaseArray($firebaseRef.requests.child($scope.uid)).$add(val);
    console.log(val) console.log($scope.request);
 }

您的问题已修复:https://plnkr.co/edit/KbVoni3jfnHm54M80kYl?p=preview

您必须等到从 userData.getUserData 获取响应的过程完成。

据我所知有3种方法可以解决这个问题:

使用回调

function getUserData(callback){
  userData.getUserData(function(response) {
    callback(response);
  });
}

然后你调用那个函数

getUserData(function(response){
  $scope.uid = response;
  // then you can proceed and use the $scope.uid here
});

将其包装在函数中

getUserData(function(response){
  callAnotherFunction(response);
});

function callAnotherFunction(response){
  console.log(response);
  // You can use the value inside this function
}

或使用超时

可以使用$timeout给请求时间,分配给$scope.uid

从你的 plunker 代码中你有一个看起来像这样的服务:

angular.module('plunker');
.service('myService', function($firebaseRef, $firebaseObject){

    this.getUserData = function(el) {
            $firebaseObject($firebaseRef.users.child(this.localStorage().uid)).$loaded(function(data) {
                el(data);
            })
        }
});

和这样的控制器:

app.controller('MainCtrl', function($scope, myService) {

 myService.getUserData(function(response) {  
   $scope.uid = response;
 })

 console.log($scope.uid);  

 $scope.postRequest = function(val) {
            $firebaseArray($firebaseRef.requests.child($scope.uid)).$add(val);
            console.log(val)
            console.log($scope.request);
        }
});

问题是第 console.log($scope.uid); 行打印 undefined.

您正在考虑标准阻塞编程,但在这种情况下,对 getUserData 的调用是非阻塞的,这意味着您不等待 response,而是您只需将请求发送到服务器 (Firebase) 并继续执行下一条语句 console.log.

回调function(response) { $scope.uid = response; }将在客户端读取服务器返回的成功响应(HTTP 2xx)时被调用。这至少需要请求传输到服务器和响应返回的时间 + 服务器实际获取数据所需的时间。例如 150ms.

所以,基本上在执行 console.log 语句时,response 回调仍然没有被调用,即。 $scope.uid 未设置,这意味着 console.log 将打印 undefined.

要解决此问题,您需要在回调本身中执行您的代码,这取决于服务器的响应。例如这样的事情:

app.controller('MainCtrl', function($scope, myService) {

  myService.getUserData(function(response) {  
    $scope.uid = response;
    console.log($scope.uid);
    // and any other code which depends on the $scope.uid
  });

  // ...

});

最酷的因素是通过 $q 服务使用 AngularJS promises。例如,您可以像这样重新定义您的服务:

angular.module('plunker');
.service('myService', function($q, $firebaseRef, $firebaseObject){
    var deferred = $q.defer();

    this.getUserData = function(el) {
            $firebaseObject($firebaseRef.users.child(this.localStorage().uid)).$loaded(function(data) {
              deferred.resolve(data);
            });
    };

    return deferred.promise;
});

然后在您的控制器中,您可以像这样使用您的服务方法:

app.controller('MainCtrl', function($scope, myService) {

 myService.getUserData()
   .then(function(data) {
     $scope.uid = data;
     console.log($scope.uid);
     // and any other code 
     // you can also return promises here and then chain
     // them, read about AngularJS promises
   });

   // ...
});

这与前面的示例基本相同,但增加了可读性更好的好处,这是通过避免回调地狱来实现的。

我注意到您有使用 $scope.uidpostRequest 函数。我猜如果你没有 $scope.uid,你不想执行这个函数。我还猜测这个函数是由某些事件调用的,比如点击一个按钮。我的建议是在加载 $scope.uid 之前禁用按钮或任何其他调用此功能的东西。 例如像这样:

<button type="button" ng-click="postRequest(something)" ng-disabled="uid === undefined">Post</button>

希望对您有所帮助。