简体   繁体   中英

Return promise inside resolve function as its continuation

Context

I'm working with Angular. I have a service called UserService , that handles login, authentication and user data requests.

The get method needs to check if the user has a valid (not expired) token for authentication before making the get request. So, if it has, make the request, if not, request a token and then make the request.

Problem

This get method needs to hide its complex requests. It has to return only a Promise as it was making only one request.

So, an example of usage:

UserService
    .get()
    .then(data => { ... })
    .catch(error => { ... })

Wrong solution

Check if the token is expired. If it is, return a request to refresh the token, and there, make and return the get request. If it is not, just make and return the get request. As below:

function get() {
    if (isTokenExpired(token))
        return $http
            .post(url + '/refreshtoken', 'token=' + refreshToken)
            .then(response => {
                token = response.data.token
                return $http.get(url + '?token=' + token)
            })
            .catch(response => { ... })
    else
        return $http.get(url + '?token=' + token)
}

But it's returning a promise that I will have to handle like this:

UserService
    .get()
    .then(request => {
        request // THAT IS NOT GOOD
            .then(data => { ... })
            .catch(error => { ... })
    })
    .catch(error => { ... })

Anything like the usage example!

Correct solution

How to make this get method on service, which handles authentication like that and hides everything from the controller that will use, letting it like in the usage example?

But it's returning a promise for a promise that I will have to handle like this:

  UserService.get().then(request => { request.then(data => { … }) }) 

No.

Promises do chain , any "promise for a promise" will implicitly be flattened to a promise for the inner result. Your "wrong solution" code simply works as is.

Here's an example. Basically you need to transform with an additional .then()

 angular.module('app', []) .service('UserService', function($http) { let url = 'https://jsonplaceholder.typicode.com'; function getUserData(token) { return $http.get(url + '/users/1', { token: token }) .then(resp => resp.data); } this.get = function(tokenIsValid) { if (!tokenIsValid){ console.log('refreshing'); return $http.post(url + '/posts', { refreshToken: 'rt' }) .then(getUserData) } return getUserData(); } return this; }) .run(function($rootScope, UserService) { $rootScope.get = (valid) => { console.log('Getting with ' + (valid? '':'in') + 'valid token'); UserService.get(valid) .then(console.log) .catch(console.error); } }); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app"> <button ng-click="get()">Get invalid</button> <button ng-click="get(true)">Get valid</button> </div> 

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