Angular 5: 从函数返回一个Observable

3
在过去,我会定义一个新的Promise,延迟它,然后在我的函数完成时解决它。 现在我发现自己处于需要从函数返回Observable的情况下,并且我想确保在Angular 5上正确设置它。
测试函数,工作正常:

getTreeViewChildren(currNode: any, nodeType: string, nodeTypeEnum: number = 0, nested: boolean = true)
                  : Observable<any> 
{

let treeObs: Observable<any>;

treeObs = new Observable(obs => {

 this.siteConfigService.getHostAccessPoints().subscribe(data => {
  let hostAccessPoints = JSON.parse(data);
  let accPointTree = this.findChildNodes(currNode, hostAccessPoints, nested);
  obs.next(accPointTree);
  obs.complete(); 
 });  
 
}); 
return treeObs;
}

我从我的NG组件成功订阅:

this.configService.getTreeViewChildren(this.selectedTreeViewItem, type, nodetype, true).subscribe(tree =>{
 let theTree = tree;
 }); 

然而实际功能具有更多的检索逻辑。根据我的测试函数,设置 Observable 的正确方法是什么?是否完全相同的模式,只是将所有代码包装在 treeObs = new Observable(..) 中?

getTreeViewChildNodes(currNode: any, nodeType: string, nodeTypeEnum: number = 0, nested: boolean = true): Observable<any> {
 let hosts;
 let locations;
 let hostAccessPoints;
 let treeResult: Observable<any>;

 if (nodeTypeEnum === NodeType.Location) {  
  // more code..
  let someTree = getStuff();
  return someTree;
 }

 if (nodeTypeEnum === NodeType.Host) {
  // more code..
  let someTree = getStuff();
  return someTree;
 }

 if (nodeTypeEnum === NodeType.HostAccessPoint) {
  let accPointTree;
  if (sessionStorage["hostAccessPoints"]) {
   // more code..
   let someTree = getStuff();
   return someTree;
  }
  else {
   this.siteConfigService.getHostAccessPoints().subscribe(data => {
    // more code..
    let someTree = getStuff();
    return someTree;
   });   
  }
 }

 if (nodeTypeEnum === NodeType.HostStorage) {
  // TO DO
 }  
  }

**** 更新(基于下面提供的 Observable.of() 建议答案):

// Builds hierarchical treeview data
  getTreeViewChildNodes(currNode: any, nodeType: string, nodeTypeEnum: number = 0, nested: boolean = true): Observable<any> {
 let hosts;
 let locations;
 let hostAccessPoints;

 
 if (nodeTypeEnum === NodeType.Location) {
  if (sessionStorage["locations"] != null && sessionStorage["locations"] != "undefined") {   
   locations = JSON.parse(  sessionStorage.getItem('locations') );
  }
  // find child nodes
  let locationTree = this.findChildren(currNode, locations, nested);     
  return Observable.of(locationTree);
 }

 if (nodeTypeEnum === NodeType.Host) {
  if (sessionStorage["hosts"] != null && sessionStorage["hosts"] != "undefined") {   
   hosts = JSON.parse(  sessionStorage.getItem('hosts') );
  }
  // find child hosts for current node
  let hostTree = this.findChildHosts(currNode, hosts, nested);  
  return Observable.of(hostTree);
 }

 if (nodeTypeEnum === NodeType.HostAccessPoint) {
  let accPointTree;
  if (sessionStorage["hostAccessPoints"]) {
   hostAccessPoints = sessionStorage.getItem("hostAccessPoints");
   accPointTree = this.findChildHostAccessPoints(currNode, hostAccessPoints, nested);   
   return Observable.of(accPointTree);
  }
  else { // **** THREW ERROR FROM CALLER 'Cannot read property 'subscribe' of undefined****`
   /*this.siteConfigService.getHostAccessPoints().subscribe(data => {
    hostAccessPoints = JSON.parse(data);
    accPointTree = this.findChildHostAccessPoints(currNode, hostAccessPoints, nested);    
    return Observable.of(accPointTree);
   });*/   
                // ** CORRECTED CODE **
                return this.siteConfigService.getHostAccessPoints().map(data => {
    hostAccessPoints = JSON.parse(data);
    accPointTree = this.findChildHostAccessPoints(currNode, hostAccessPoints, nested);    
    return accPointTree;
   });      
      
  }
 }
  }

从我的组件代码中,仅当我调用我的服务并进而调用http.get()时,它会抛出一个错误TypeError: Cannot read property 'subscribe' of undefined:

 this.configService.getTreeViewChildNodes(this.selectedTreeViewItem, type, nodetype, true).subscribe(data => {
        this.rebuildNetworkTree(data);
    });
2个回答

4
也许你应该使用一个主题,类似这样:
let treeSubj = new Subject<any>();
let treeResult = this.treeSubj.asObservable();
// a lot of code
// need to tick a value in treeResult somewhere - can do this in several places
this.treeSubj.next(yourValue)


// and then somewhere need to get that result

this.treeResult.subscribe(tree => doSomething(tree));

每次调用treeSubj.next(value)时,您的treeResult订阅者都会收到该值。

在我的情况下,我的组件方法仍然需要显式调用 getTreeViewChildNodes(currNode: any, nodeType: string, nodeTypeEnum: number = 0, nested: boolean = true)。对于 Subject,订阅者将等待结果。这就是我困惑的地方,不知道如何像你建议的那样使用 Subject - bob.mazzo

4
我无法准确了解你的第二个示例尝试返回什么细节,但更好的方法是不使用 new Observable(...) 这些。最好只使用map操作符来转换数据。
getTreeViewChildren(currNode: any, nodeType: string, nodeTypeEnum: number = 0, nested: boolean = true): Observable<any> {
    return this.siteConfigService.getHostAccessPoints().map(data => {
        let hostAccessPoints = JSON.parse(data);
        let accPointTree = this.findChildHostAccessPoints(currNode, hostAccessPoints, nested);

        return 'test123';
    });
}

来自评论的更新:
如果您有一个函数,有时使用异步操作,有时不使用,您可以利用Observable.of()来处理非异步返回值:
getTreeViewChildNodes(currNode: any, nodeType: string, nodeTypeEnum: number = 0, nested: boolean = true): Observable<any> {
    if (doSynchronousWork) {        
        // more code..
        let someTree = getStuff();
        return Observable.of(someTree);
    }

    if (doAsynchronousWork) {
        return this.siteConfigService.getHostAccessPoints().map(data => {
            // more code..
            let someTree = getStuff();
            return someTree;
        });
    }
}

所以 getTreeViewChildNodes() 并不总是订阅另一个服务;有时它只是从 localStorage 中获取数据,应用一些解析逻辑,然后将结果返回给调用者。其他时候,getTreeViewChildNodes() 可能需要订阅一个服务,然后返回数据树结果。所以我想我试图应用 Observable 模式(即我以前用来创建/延迟/解决旧的 Promise 的方式)。 - bob.mazzo
1
我喜欢Observable.of()的想法。实际上,我的组件方法需要subscribeconfigService.getTreeViewChildNodes(),所以我认为在每个if条件之后需要返回Observable.of()。我的意思清楚吗? - bob.mazzo
1
@bob.mazzo 每个你返回someTreeif语句都可以利用this.siteConfigService.getHostAccessPoints()调用它。 Observable.of(...)仅创建一个发出单个值的可观察对象。 - Daniel W Strimpel
当调用doAsynchronousWork时,我收到了Cannot read property 'subscribe' of undefined的错误。我通过调用我的http服务来获取AccessPoints数组,这样做是否会取消Observable? - bob.mazzo
1
@bob.mazzo,你不需要在那里使用 subscribe。改用 map 并且不要返回 Observable.of(accPointTree),而是直接返回 accPointTree - Daniel W Strimpel
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接