簡體   English   中英

並行激活異步請求,但使用rxjs按順序獲取結果

[英]Fire async request in parallel but get result in order using rxjs

例如:

使用jquery ajax在parrallel中獲取5頁。 當page2返回時,什么都不做。 當page1返回時,使用page1和page2執行某些操作。

// assume there is some operator that can do this, 
// then it might look like this?
Rx.Observable.range(1, 5).
someOperator(function(page) {
  return Rx.Observable.defer( () => $.get(page) );
}).scan(function(preVal, curItem) {
  preVal.push(curItem);
  return preVal;
}, []);

存在forkJoin運算符,它將run all observable sequences in parallel and collect their last elements. (引自文獻)。 但是如果你使用那個,你將不得不等待所有5個承諾解決,或者5個中的一個出錯。 它與RSVP.alljQuery.when 因此,一旦你擁有第二個,就不會允許你做某事。 無論如何,我提到它,以防它在另一種情況下對你有用。

另一種可能性是使用concatMap ,它允許您按順序接收已解決的promise。 但是,我並不清楚它們是否會並行啟動,第二個承諾應該只在第一個承諾解決時開始。

我能想到的最后一個選項是使用merge(2) ,它應該並行運行兩個promise,並且在任何時候它們只會被“啟動”兩個promise。

現在,如果您不使用defer ,並且使用concatMap ,我相信您應該已經啟動了所有AJAX請求,並且仍然是正確的排序。 所以你可以寫:

.concatMap(function(page) {
  return $.get(page);
})

相關文件:

concatMap保持順序,但按順序處理元素。

mergeMap不保持順序,但它並行運行。

我在下面創建了運算符mergeMapAsync,以便並行生成流程元素(例如頁面下載),但按順序發出。 它甚至支持限制(例如,並行下載最多6頁)。

 Rx.Observable.prototype.mergeMapAsync = mergeMapAsync; function mergeMapAsync(func, concurrent) { return new Rx.Observable(observer => { let outputIndex = 0; const inputLen = this.array ? this.array.length : this.source.array.length; const responses = new Array(inputLen); const merged = this.map((value, index) => ({ value, index })) // Add index to input value. .mergeMap(value => { return Rx.Observable.fromPromise(new Promise(resolve => { console.log(`${now()}: Call func for ${value.value}`); // Return func retVal and index. func(value.value).then(retVal => { resolve({ value: retVal, index: value.index }); }); })); }, concurrent); const mergeObserver = { next: (x) => { console.log(`${now()}: Promise returned for ${x.value}`); responses[x.index] = x.value; // Emit in order using outputIndex. for (let i = outputIndex, len = responses.length; i < len; i++) { if (typeof responses[i] !== "undefined") { observer.next(responses[i]); outputIndex = i + 1; } else { break; } } }, error: (err) => observer.error(err), complete: () => observer.complete() }; return merged.subscribe(mergeObserver); }); }; // ---------------------------------------- const CONCURRENT = 3; var start = Date.now(); var now = () => Date.now() - start; const array = ["a", "b", "c", "d", "e"]; Rx.Observable.from(array) .mergeMapAsync(value => getData(value), CONCURRENT) .finally(() => console.log(`${now()}: End`)) .subscribe(value => { console.log(`${now()}: ${value}`); // getData }); function getData(input) { const delayMin = 500; // ms const delayMax = 2000; // ms return new Promise(resolve => { setTimeout(() => resolve(`${input}+`), Math.floor(Math.random() * delayMax) + delayMin); }); } 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>mergeMapAsync</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.min.js"></script> </head> <body> </body> </html> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM