【Angular】同步異步處理

轉自:https://rxjs-cn.github.io/learn-rxjs-operators/operators/combination/forkjoin.html

遇到一個angular異步請求的問題,需要同時調用六七個接口,後面的操作是基於這六七個接口的返回結果的。

用forkJoin,正好可以解決,網上的一些例子都不適用。

 

函數簽名: forkJoin(...args, selector : function): Observable

當所有 observables 完成時,發出每個 observable 的最新值。


:bulb: 如果你想要多個 observables 按發出順序相對應的值的組合,試試 zip

:warning: 如果內部 observable 不完成的話,forkJoin 永遠不會發出值!


爲什麼使用 forkJoin

當有一組 observables,但你只關心每個 observable 最後發出的值時,此操作符是最適合的。此操作符的一個常見用例是在頁面加載(或其他事件)時你希望發起多個請求,並在所有請求都響應後再採取行動。它可能與 Promise.all 的使用方式類似。

注意,如果任意作用於 forkJoin 的內部 observable 報錯的話,對於那些在內部 observable 上沒有正確 catch 錯誤,從而導致完成的 observable,你將丟失它們的值 (參見示例 4)。如果你只關心所有內部 observables 是否成功完成的話,可以在外部捕獲錯誤

還需要注意的是如果 observable 發出的項多於一個的話,並且你只關心前一個發出的話,那麼 forkJoin並非正確的選擇。在這種情況下,應該選擇像 combineLatest 或 zip 這樣的操作符。

 

示例

示例 1: Observables 再不同的時間間隔後完成

StackBlitz | jsBin | jsFiddle )

// RxJS v6+
import { delay, take } from 'rxjs/operators';
import { forkJoin, of, interval } from 'rxjs';

const myPromise = val =>
  new Promise(resolve =>
    setTimeout(() => resolve(`Promise Resolved: ${val}`), 5000)
  );

/*
  當所有 observables 完成時,將每個 observable 
  的最新值作爲數組發出
*/
const example = forkJoin(
  // 立即發出 'Hello'
  of('Hello'),
  // 1秒後發出 'World'
  of('World').pipe(delay(1000)),
  // 1秒後發出0
  interval(1000).pipe(take(1)),
  // 以1秒的時間間隔發出0和1
  interval(1000).pipe(take(2)),
  // 5秒後解析 'Promise Resolved' 的 promise
  myPromise('RESULT')
);
//輸出: ["Hello", "World", 0, 1, "Promise Resolved: RESULT"]
const subscribe = example.subscribe(val => console.log(val));

 

示例 2: 發起任意多個請求

StackBlitz | jsBin | jsFiddle )

// RxJS v6+
import { mergeMap } from 'rxjs/operators';
import { forkJoin, of } from 'rxjs';

const myPromise = val =>
  new Promise(resolve =>
    setTimeout(() => resolve(`Promise Resolved: ${val}`), 5000)
  );

const source = of([1, 2, 3, 4, 5]);
// 發出數組的全部5個結果
const example = source.pipe(mergeMap(q => forkJoin(...q.map(myPromise))));
/*
  輸出:
  [
   "Promise Resolved: 1",
   "Promise Resolved: 2",
   "Promise Resolved: 3",
   "Promise Resolved: 4",
   "Promise Resolved: 5"
  ]
*/
const subscribe = example.subscribe(val => console.log(val));

 

示例 3: 在外部處理錯誤

StackBlitz | jsBin | jsFiddle )

// RxJS v6+
import { delay, catchError } from 'rxjs/operators';
import { forkJoin, of, throwError } from 'rxjs';

/*
  當所有 observables 完成時,將每個 observable 
  的最新值作爲數組發出
*/
const example = forkJoin(
  // 立即發出 'Hello'
  of('Hello'),
  // 1秒後發出 'World'
  of('World').pipe(delay(1000)),
  // 拋出錯誤
  _throw('This will error')
).pipe(catchError(error => of(error)));
// 輸出: 'This will Error'
const subscribe = example.subscribe(val => console.log(val));

 

示例 4: 當某個內部 observable 報錯時得到成功結果

StackBlitz | jsBin | jsFiddle )

// RxJS v6+
import { delay, catchError } from 'rxjs/operators';
import { forkJoin, of, throwError } from 'rxjs';

/*
  當所有 observables 完成時,將每個 observable 
  的最新值作爲數組發出
*/
const example = forkJoin(
  // 立即發出 'Hello'
  of('Hello'),
  // 1秒後發出 'World'
  of('World').pipe(delay(1000)),
  // 拋出錯誤
  _throw('This will error').pipe(catchError(error => of(error)))
);
// 輸出: ["Hello", "World", "This will error"]
const subscribe = example.subscribe(val => console.log(val));

 

示例 5: Angular 中的 forkJoin

plunker )

@Injectable()
export class MyService {
  makeRequest(value: string, delayDuration: number) {
    // 模擬 http 請求
    return of(`Complete: ${value}`).pipe(
      delay(delayDuration)
    );
  }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>forkJoin Example</h2>
      <ul>
        <li> {{propOne}} </li>
        <li> {{propTwo}} </li>
        <li> {{propThree}} </li>
      </ul>
    </div>
  `,
})
export class App {
  public propOne: string;
  public propTwo: string;
  public propThree: string;
  constructor(private _myService: MyService) {}

  ngOnInit() {
    // 使用不同的延遲模擬3個請求
    forkJoin(
      this._myService.makeRequest('Request One', 2000),
      this._myService.makeRequest('Request Two', 1000),
      this._myService.makeRequest('Request Three', 3000)
    )
    .subscribe(([res1, res2, res3]) => {
      this.propOne = res1;
      this.propTwo = res2;
      this.propThree = res3;
    });
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章