2016-08-10 28 views
5

我正在用Angular2開發一個Web應用程序,並且從服務器獲取數據時遇到了一些問題。如何在Angular 2中「鏈接」兩個獨立的可觀察對象

import ... 

@Component({ 
... 

}) 
export class EmployeeManagementTableComponent implements OnInit, OnDestroy{ 

private employees: Employee[]; 
private departments: SelectItem[] = []; 
private selectedDepartment: string; 
private columns: any[]; 
private paramSub: any; 
private employeesSub: any; 
private departmentSub: any; 


constructor(private employeeManagementService: EmployeeManagementService, 
      private route: ActivatedRoute, 
      private router: Router, 
      private ccs: ComponentCommunicatorService, 
      private logger: Logger) { } 

ngOnInit(){ 

    this.columns = [ 
    ... 
    ]; 

    //ccs is just a service for storing/getting app wide infomation 

    this.selectedDepartment = this.ccs.getSelectedDepartment(); 
    this.getDepartments(); 
    this.getEmployees(this.selectedDepartment); 

    ... 
} 

ngOnDestroy(){ 
    /*this.employeesSub.unsubscribe(); 
    this.departmentDub.unsubscribe();*/ 
} 

getDepartments(){ 

    this.departments.push({label: 'Alle', value: 'all'}); 

    this.departmentSub = this.employeeManagementService.getDepartments().subscribe(
      data => {data.forEach((item, index) => { 
         this.departments.push({label: item, value: index.toString()}); 
        });  
        }, 
      err => this.logger.error(err), 
     () => {this.logger.log('done loading'); 
       this.departmentSub.unsubscribe()} 
    ); 
} 
getEmployees(department: any){ 

this.employeesSub = this.employeeManagementService.getEmployees(department).subscribe(
      data => {this.employees = data}, 
      err => this.logger.error(err), 
     () => {this.logger.log('done loading'); 
       this.employeesSub.unsubscribe()} 
    ); 
} 

正如你看到組件初始化時它調用兩個獲取數據的方法。這些方法從我的服務中獲得可觀察的並訂閱它們。
問題是,訂單就像call1, call2, result1, result2, ...,我認爲有不對的地方。應該是call1, result1, call2, result2, ...還是我錯了?我試着在observable1的onComplete中訂閱observable2,但我認爲專用方法當時是無用的。 我已經研究並找到了一些解決方案,同時用concat同時訂閱兩個observables,但是我只希望getDepartments()在所有數據流量完成時繼續執行代碼。

而且我應該取消訂閱OnDestroy()OnCompletesubscribe函數,我真的沒有什麼區別嗎?

回答

8

如果要控制可觀察的執行順序,就需要建立像flatMap(串聯執行)或Observable.forkJoin(以並行執行)

下面是樣本異步數據流利用操作符:

// Series 
someObservable.flatMap(result1 => { 
    return someOtherObservable; 
}).subscribe(result2 => { 
    (...) 
    (...) 
}); 

// Parallel 
Observable.forkJoin([ someObservable, someOtherObservable ]) 
    .subscribe(results => { 
    let result1 = results[0]; 
    let result2 = results[1]; 
    }); 
+0

正如我理解'forkJoin',它會給我我的員工和部門在一個可觀察的。但我希望我的兩種方法保持獨立。這也是可能的嗎?地圖也是我不明白的事情。什麼是'flatMap'在做什麼?我試圖查找它,但我仍然沒有得到'地圖'的目的。 – moessi774

+0

它們將並行執行,但是在同一個異步數據流中執行。您可以將您的處理實現爲兩種不同的方法。唯一的限制是它們同時返回一個可觀察對象... –

+0

map和flatMap之間的不同之處在於,第一個返回原始對象,而第二個可以參與數據流的可觀察對象。這個視頻可以幫助你理解和看到不同的行動:https://egghead.io/lessons/rxjs-rxjs-map-vs-flatmap ;-) –

0

通常,這些調用是異步的,因此執行順序和/或到達結果不是確定性的。 (例如:如果從API 1請求數據,然後從API 2請求數據,那麼甚至可能導致API 2的數據在API 1的數據速度特別慢或數據量巨大之前到達API 1的數據之前到達)。第一個問題:是的,你錯了。

訂閱Observable時,您可能會有一些回調函數(數據接收的地方被使用或存儲),一旦數據到達,第一個服務就會執行該函數。如果僅在接收到第一個呼叫的結果後觸發第二個API調用很重要,則該功能將是從第二個服務請求數據的地方。 當然,您不希望將服務1和服務2耦合在一起,所以更好的方法是將回調函數傳遞給服務1,服務1將在成功時調用。然後,您的客戶端代碼可以確保此回調函數請求來自第二個服務的數據。當然,如何處理這種情況有很多種方法,而我之前描述的只是一種簡單的方法。

關於取消訂閱問題:通常,在接收結果時不希望取消訂閱,因爲之後可能會有更多數據進入。 (這是Promises和Obvservables之間的主要區別之一)。例如,在我正在處理的應用程序中,當我「離開」組件時取消訂閱,因爲我想在我收到初始數據後繼續訂閱。

+0

謝謝你的快速回答。數據服務是一個運行了一些'jsp'的apache tomcat。我現在用幾年的初學java知識進行編程。但我真的不明白我應該怎麼做/處理整個回調的事情。你能否解釋一些更詳細的?對不起,我基本上停留在基礎知識上。 – moessi774

+0

而且取消訂閱它對我來說基本上是一樣的,如果我取消訂閱可觀察的OnDestroy或OnComplete?唯一的區別是,如果我仍然訂閱和服務器數據變化,我收到一個新的觀察。對? – moessi774