如何在Angular 2中平面化嵌套的可观察对象
How to flatten nested Observables in Angular 2
我是一个新手。我用它们来检查用户是否在我的根页面的构造函数中登录。
为了做到这一点,我嵌套了许多可观察对象,它们工作得很好,但我认为有一种方法可以使所有这些嵌套的可观察对象变平。
我只是想让你检查一下代码,让我知道有什么可以改进的,如果我能在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
}
)
}
供应商/user-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)
}
}
要传递参数并从一个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
})
感谢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.
})
})
}
}
IMHO这是我能够基于switchMap
生成的最好的代码版本,如果有人能想到一个更好的版本,请建议它。
相关文章:
- 用嵌套函数和默认函数定义函数
- 如何在ReactJS JSX中执行嵌套的if-else语句
- 可以简化嵌套的延迟Q Promises解析吗
- 用于搜索的聚合物嵌套绑定
- 如何使用javascript获取嵌套对象中所有子对象的单个属性
- d3中堆栈函数和嵌套函数之间的差异
- 如何打印嵌套对象的所有值
- JavaScript 中的嵌套函数和 “this” 关键字
- 设置嵌套对象属性的更好方法
- querySelector/getElementByClassName嵌套项的顺序
- 将js对象更改为使用嵌套的可观察数组敲除js视图模型
- Knockoutjs观察嵌套对象并订阅更改
- 剑道模板使用嵌套/多维可观察
- 嵌套在 KnockoutJS 中可观察
- 挖空嵌套模型可观察数组未定义
- 是否有可能在运算符内部返回新的可观察项,嵌套可观察项
- Angular 2 rxjs的嵌套观察对象
- 扁平化嵌套的可观察对象
- 如何在Angular 2中平面化嵌套的可观察对象
- 余烬观察嵌套模型属性