简体   繁体   中英

How to achieve something similar to C#'s await in AngularJS or Javascript?

I'm working on a project which requires me to enable my users to sign-in using Google for which I'm using the Google API client (reference for which can be found here ).

Now my code is something like this.

File: services/auth-service.js

angular.module('myApp')
  .factory('gapi', function ($q) {

    var auth2;

    gapi.load('auth2', function () {
      auth2 = gapi.auth2.init({
        client_id: '649922003965-ni9e6nad25dh3ejoll70va550kt7cu5u.apps.googleusercontent.com'
      });
    });

    return {
      isSignedIn: function () {
        return auth2.isSignedIn.get();
      }
    }
  });

File: controllers/dashboard.js

angular.module('myApp')
  .controller('DashboardCtrl', function (gapi) {
      alert(gapi.isSignedIn());
  });

Now the problem is that, when alert() command is ran in the dashboard.js file, by that time auth2 hasn't loaded (because it loads from the Google API via internet I guess) therefore I get an error that isSignedIn can't be called off undefined.

So what I would ideally need is probably something like a C# await function which waits for the value to be returned and them calls off it's method. Any solutions would be really appreciated. I've spent hours trying promises, and other approaches but I was not able to get any of them to work.

UPDATE: Most of your answers would work in the scenario mentioned above. Let's try this scenario which is more complex and should've been mentioned in the first place. (Sorry for that).

File: scripts/app.js

.state('main', {
   url: '/admin',
   abstract: 'true',
   templateUrl: 'views/main.html',
   resolve: {
     check: function ($q, auth) {
       if(!auth.isSignedIn())
       {
          $q.reject({authenticated: 'false'});
       }
     }
   }
 })
 .state('admin', {
   url: '',
   parent: 'main',
   templateUrl: 'views/admin.html'
 })

Now, if I use promises here, angular wouldn't wait for the promise to be resolved. It would simple load the view and calling $q.reject after the view has been loaded will be of no use.

You can achieve this using promises in this way:

File: services/auth-service.js

angular.module('myApp')
  .factory('gapi', function ($q) {

    var auth2;
    var isSignedInDeferred = $q.defer();

    gapi.load('auth2', function () {
      auth2 = gapi.auth2.init({
        client_id: '649922003965-ni9e6nad25dh3ejoll70va550kt7cu5u.apps.googleusercontent.com'
      });
      isSignedInDeferred.resolve(auth2.isSignedIn.get());
    });

    return {
      isSignedIn: function () {
        return isSignedInDeferred.promise;
      }
    }
  });

File: controllers/dashboard.js

angular.module('myApp')
  .controller('DashboardCtrl', function (gapi) {
      gapi.isSignedIn().then(isSigned) {
          alert(isSigned);
      }
  });

Just change your isSignedIn function to return promise and resolve that promise when you have the value.

The feature is available on drafts for ES7, babel (a transpiler) has support for async/await if you feel comfortable with it. That being said, this can be done easily with just promises:

gapi.client.load(name, version, callback)

Loads the client library interface to a particular API. If a callback is not provided, a promise is returned . The loaded API interface will be in the form gapi.client.api.collection.method. For example, the Moderator API would create methods like gapi.client.moderator.series.list.

The api already gives you back a promise, so no need to wrap it around q , all you need to do is return that promise:

return gapi.load('auth2').then(function() {
    return gapi.auth2.init({
       client_id: '649922003965-ni9e6nad25dh3ejoll70va550kt7cu5u.apps.googleusercontent.com'
    });
});

Now, from your controller:

gapi.then(function(auth2){
  //auth2 already loaded
});

Edit: Assuming you can get the returned promise on your check function. All you need to is:

var possiblyRejectedPromise = gapi.then(function(auth2){
   if(!auth2.isSignedIn.get()){
       throw new Error('Not logged in');
   } else {
       //LoggedIn
       return true;
   }
 });
return possiblyRejectedPromise;

There is no equivalent to await in ES5. You need to get into the mindset of handling events as they happen and updating your application state based on those events.

For your specific issue, I believe you are correct in your assumption that it is failing because the auth2 variable has not been set (and therefore is undefined). The "auth2 undefined" state is one of the application states that your code needs to handle. The solution may be as simple as changing your isSignedIn function like this:

isSignedIn: function () {
    return auth2 && auth2.isSignedIn.get();
}

This way it will only return true when the auth2 variable has been set and the isSignedIn property is true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM