如何在Angular 2中展平嵌套的Observable

时间:2016-10-23 14:05:10

标签: javascript angularjs angular nested observable

我是Observables的新手。我正在使用它们来检查用户是否在我的根页的构造函数中登录。

为了做到这一点,我已经嵌套了许多Observable,并且它们工作正常,但我认为有一种方法可以压缩所有这些嵌套的Observable。

我只是希望您查看代码并让我知道可以改进的内容,以及我是否可以在login-page.ts

中展平这些Observable

pages/login-page/login-page.ts



export class LoginPage {
  constructor(public navCtrl: NavController, private userService: UserService, private storage: Storage) {
        this.userService.getStoredToken().subscribe(
            data => {
                console.log('Token and username are stored.')
                this.userService.checkTokenValidity(data[0], data[1]).subscribe(
                    () => {
                        console.log('Token and username and valid.')
                        // Go to the homepage
                        this.navCtrl.push(TabsPage)
                    }, err => {
                        console.log("Invalid token, trying the stored username and password.")
                        this.userService.getStoredUserAndPassFromStorage().subscribe(data => {
                            console.log('Successfuly retrieved the username and password')
                            this.userService.login(data[0], data[1]).subscribe((res) => {
                                console.log('Username and password are valid.')
                                // Go to the homepage
                                this.navCtrl.push(TabsPage)
                                // Save new user data to local storage
                                this.userService.authSuccess(res.access_token, data[0], data[1])
                            }, err => {
                                console.log("Failed to login using the stored username and password.")
                                //Remove the loading and show login form
                            })
                        }, err => {
                            console.log("No stored token.")
                            //Remove the loading the and login form
                        })
                    }
                )
            },
            err => {
                //Remove the loading the show login form
            }
        )
    }




提供商/用户service.ts



export class UserService {
    loginDetails: ILogin
    headers: any
    error: string
    
    apiUrl = global.apiUrl
    loginUrl = api.loginUrl
    
    contentHeader: Headers = new Headers({'Content-Type': 'application/json'})
    
    constructor(public http: Http, private storage: Storage) {
    }
    
    logout() {
        this.storage.remove('_user')
        this.storage.remove('_pass')
        this.storage.remove('_token')
    }
    
    login(username: string, password: string): Observable<IAccessToken> {
        this.loginDetails = {
            client_id: global.clientId,
            client_secret: global.clientSecret,
            grant_type: 'password',
            username: username,
            password: password,
        }
        let body = JSON.stringify(this.loginDetails)
        let options = new RequestOptions({headers: this.contentHeader})
        
        return this.http
                   .post(this.loginUrl, body, options)
                   .map(response => response.json())
    }
    
    getStoredToken(): Observable<string[]> {
        return Observable.forkJoin(
            this.storage.get('_token'),
            this.storage.get('_user')
        )
    }
    
    getStoredUserAndPassFromStorage(): Observable<string[]> {
        return Observable.forkJoin(
            this.storage.get('_user'),
            this.storage.get('_pass')
        )
    }
    
    checkTokenValidity(token: any, username: any): Observable<IAccessToken> {
        let params = new URLSearchParams()
        params.set('access_token', token)
        params.set('_format', 'json')
        return this.http.get(api.userInfoUrl(username), {
            search: params
        }).map(response => response.json())
    }
    
    authSuccess(access_token, username, password) {
        this.error = null
        this.storage.set("_user", username)
        this.storage.set("_pass", password)
        this.storage.set("_token", access_token)
    }
}
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

要从Observable传递参数并启动新的Observable,您可以使用switchMap运算符。 在你的情况下,这将是

this.userService.getStoredToken().switchMap(data =>

   this.userService.checkTokenValidity(data[0], data[1]).switchMap(isvalid =>

      this.userService.getStoredUserAndPassFromStorage().switchMap(data =>

          this.userService.login(data[0], data[1]).subscribe((res) => {
                                console.log('Username and password are valid.')
                                // Go to the homepage
                                this.navCtrl.push(TabsPage)
                                // Save new user data to local storage
                                this.userService.authSuccess(res.access_token, data[0], data[1])
                            }, err => {
                                console.log("Failed to login using the stored username and password.")
                                //Remove the loading and show login form
                            })

答案 1 :(得分:0)

感谢Alexander在这种情况下指出switchMap的好处。

我已经使用了你的解决方案,并且我已经做了一些重构,以确保它尽可能的可读。

export class LoginPage {
    login: ILogin
    
    constructor(public navCtrl: NavController, private userService: UserService, private storage: Storage) {
        this.forgotPasswordPage = ForgotPasswordPage
        this.checkIfUserIsLoggedIn();
    }
    
    checkIfUserIsLoggedIn() {
        const storedToken$ = this.userService.getStoredToken()
        const checkTokenValidity$ = (data) => this.userService.checkTokenValidity(data[0], data[1])
        const storedUserAndPass$ = this.userService.getStoredUserAndPassFromStorage();
        const login$ = (data) => this.userService.login(data)
        
        const checkStoredTokenValidity$ = storedToken$.switchMap(data => checkTokenValidity$(data))
        const loginUsingStoredUsernameAndPass$ = storedUserAndPass$.switchMap(data => login$(data))
        
        checkStoredTokenValidity$.subscribe(() => {
            this.navCtrl.push(TabsPage)
        }, () => {
            console.log('Invalid token, now trying the saved username and password');
            loginUsingStoredUsernameAndPass$.subscribe(res => {
                this.navCtrl.push(TabsPage)
                this.userService.updateToken(res.access_token)
            }, () => {
                console.log('Invalid stored username and pass, they possibly just got changed.')
                //Remove the loading animation to show the login form.
            })
        })
    }
}

恕我直言这是我能够根据switchMap生成的最佳代码版本。如果有人能想到更好的版本,请提出建议。