如何从订阅中返回 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】:

难道我们不能将pipeimport 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 但他想返回 Observable 的代码【参考方案3】:

如果要订阅 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的主要内容,如果未能解决你的问题,请参考以下文章

角度2如何从订阅返回数据

如何从订阅另一个函数的observable的函数返回布尔值?

从订阅打字稿返回值

如何从订阅内部函数中获取价值?离子 3

Angular 6 - 无法订阅从服务返回的数据

向 MailChimp 添加新订阅者返回错误请求