如何从订阅中返回 observable
Posted
技术标签:
【中文标题】如何从订阅中返回 observable【英文标题】:How to return observable from subscribe 【发布时间】:2017-02-17 13:03:05 【问题描述】:当我在订阅者中获得某个值时,我试图返回一个 observable,但我失败了。
这是代码:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>
// get route to be activated
this.routeToActivate = route.routeConfig.path;
// get user access levels
return this._firebase.isUserAdmin <-- returns Subscription, not Observable
.map(user => user.access_level)
.subscribe( access =>
// I need to return an observable here
);
关于 Angular 2 中的 observables 的资源并不多,所以我不知道从哪里开始。请问有人可以帮忙吗?
更新 -> 工作版本
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>
// get route to be activated
this.routeToActivate = route.routeConfig.path;
// get user access levels
return this._firebase.isUserAdmin
.map(user =>
let accessLevel = user.access_level;
if (accessLevel === 'admin' )
return true;
).first();
【问题讨论】:
你应该在 rxjs 而不是 ng2 中搜索 Observables。有大量的资源 谢谢!我试过了,但它们的格式与 Angular 2 使用的格式不同。我想我必须从头开始学习。 你能进一步解释这段代码的上下文吗?由于subscribe
返回Subscription
对象以取消订阅,因此不可链接,通常你想做observable.subscribe(...); return observable
。
Angular 使用 rxjs5。许多资源都是关于 rxjs4 的。我想这就是你所说的“不要采用相同的格式”(github.com/ReactiveX/rxjs == V5 vs github.com/Reactive-Extensions/RxJS == V4)
【参考方案1】:
您不能从 subscribe 返回 observable,但如果您使用 map
而不是 subscribe
,则会返回 Observable
。
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>
// get route to be activated
this.routeToActivate = route.routeConfig.path;
// get user access levels
return this._firebase.isUserAdminObservable
.map(user =>
// do something here
// user.access_level;
return true;
)
.first(); // for the observable to complete on the first event (usually required for `canActivate`)
// first needs to be imported like `map`, ...
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>
// get route to be activated
this.routeToActivate = route.routeConfig.path;
let subject = new Subject();
// get user access levels
this._firebase.isUserAdminObservable
.map(user =>
let accessLevel = user.access_level;
if (accessLevel === 'admin' )
subject.emit(true);
subject.complete();
return user;
);
return subject;
【讨论】:
您好,感谢您的回答!我需要根据值在 subscribe 内部进行一些处理,然后返回 true|false 就是这样。现在没有错误,但是路由仍然没有解锁,尽管它发送的是 true。我会尝试摆弄它并让它工作,也许我会在这个过程中学到一些东西。非常感谢! 抱歉,我的意思是 map 函数似乎采用了一个 lambda,它可以访问其范围之外的变量。但我想这就是 lambdas 可以做的——这让我有点吃惊。不过,解决了我的问题! @anytoe 对,没有办法阻止这种情况。你自己处理好了。 @GünterZöchbauer,您能否更新答案以包含RxJS 6.0
代码?【参考方案2】:
难道我们不能将pipe
与import map from 'rxjs/operators';
中的map
一起使用吗?
import map from 'rxjs/operators';
@Injectable(
providedIn: 'root'
)
export class SearchHostService
constructor(private readonly http: HttpClient)
searchForHosts(searchString: string): Observable<Employee[]>
return this.http
.get<Employee[]>('./assets/host-users.json')
.pipe(
map(employees =>
employees.filter(( displayName ) =>
displayName.toLowerCase().startsWith(searchString),
),
),
);
【讨论】:
但是如果我们不返回 Observable如果要订阅 observable,请执行此操作,处理结果,然后在订阅中返回相同的结果:
function xyx(): Observable<any>
const response = someFunctionThatReturnsObservable().pipe(map(result =>
// here do any processing of the result //
return result; // return back same result.
))
return response;
【讨论】:
【参考方案4】:我们可以使用toPromise
方法将 Observable 对象转换为 Promise。
所以代码可以实现如下:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Promise<boolean>
// get route to be activated
this.routeToActivate = route.routeConfig.path;
// get user access levels
return this._firebase.isUserAdmin
.map(user =>
return (user.access_level === 'admin');
).toPromise();
【讨论】:
【参考方案5】:你不需要map,下面的代码为first指定了一个谓词和一个投影函数。
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>
this.routeToActivate = route.routeConfig.path;
return this._firebase.isUserAdminObservable
.first((_, index) => index === 0, user =>
// do something here
// user.access_level;
return true;
)
More on first
【讨论】:
【参考方案6】:您可以创建一个新的 observable,并根据access
级别触发事件。
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean>
// get route to be activated
this.routeToActivate = route.routeConfig.path;
// get user access levels
return new Observable(subscriber=>
this._firebase.isUserAdmin
.map(user => user.access_level)
.subscribe(access =>
// Return an observable!
// Change your logic here...
return access === XXX ? subscriber.next(true) : subscriber.next(false);
, err => subscriber.error());
)
参考:https://rxjs-dev.firebaseapp.com/guide/observable
【讨论】:
以上是关于如何从订阅中返回 observable的主要内容,如果未能解决你的问题,请参考以下文章