傳送多個順序 HTTP 請求
製作一系列 HTTP 請求有兩個主要原因:
-
請求相互依賴(連續請求需要一個請求的結果)。
-
我們希望將伺服器負載分散到多個請求中。
1.發出多個相關請求
這可以使用 concatMap()
運算子來執行,以將一個響應轉換為連續請求所需的引數。
function mockHTTPRequest(url) {
return Observable.of(`Response from ${url}`)
.delay(1000);
}
function timestamp() {
return (new Date()).getTime() - start;
}
var start = (new Date()).getTime();
Observable.of('url-1')
// first request
.concatMap(url => {
console.log(timestamp() + ': Sending request to ' + url);
return mockHTTPRequest(url);
})
.do(response => console.log(timestamp() + ': ' + response))
// second request
.concatMap(response => {
console.log(timestamp() + ': Sending request to ' + response);
let newUrl = 'url-' + response.length; // create new requests url
return mockHTTPRequest(newUrl);
})
.do(response => console.log(timestamp() + ': ' + response))
// third request
.concatMap(response => {
console.log(timestamp() + ': Sending request to ' + response);
let newUrl = 'url-' + response.length; // create another requests url
return mockHTTPRequest(newUrl);
})
.subscribe(response => console.log(timestamp() + ': ' + response));
運算子 concatMap()
在內部訂閱 Observable 從其投影函式返回,並等待它完成,同時重新發出其所有值。
此示例為每個請求和響應新增時間戳:
3: Sending request to url-1
1010: Response from url-1
1011: Sending request to Response from url-1
2014: Response from url-19
2015: Sending request to Response from url-19
3017: Response from url-20
檢視現場演示: https : //jsbin.com/fewidiv/6/edit?js,console
處理錯誤
如果任何 HTTP 請求失敗,我們顯然不想繼續,因為我們無法構造以下請求。
2.連續提出請求
如果我們對之前的 HTTP 請求的響應不感興趣,我們可以只獲取一個 URL 陣列並一個接一個地執行它們。
function mockHTTPRequest(url) {
return Observable.of(`Response from ${url}`)
.delay(1000);
}
let urls = ['url-1', 'url-2', 'url-3', 'url-4'];
let start = (new Date()).getTime();
Observable.from(urls)
.concatMap(url => mockHTTPRequest(url))
.timestamp()
.map(stamp => [stamp.timestamp - start, stamp.value])
.subscribe(val => console.log(val));
此示例列印帶時間戳的響應:
[1006, "Response from url-1"]
[2012, "Response from url-2"]
[3014, "Response from url-3"]
[4016, "Response from url-4"]
觀看現場演示: https : //jsbin.com/kakede/3/edit?js,console
延遲連續的通話
我們可能還想在每個請求之間做一個小延遲。在這種情況下,我們需要在每次 mockHTTPRequest()
呼叫後附加 delay()
。
Observable.from(urls)
.concatMap(url => {
return mockHTTPRequest(url)
.do(response => console.log(((new Date()).getTime() - start) + ': Sending request to ' + url))
.delay(500);
})
.timestamp()
.map(stamp => [stamp.timestamp - start, stamp.value])
.subscribe(val => console.log(val));
這將列印到控制檯以下輸出:
2024: Sending request to url-1
[2833, "Response from url-1"]
4569: Sending request to url-2
[5897, "Response from url-2"]
7880: Sending request to url-3
[8674, "Response from url-3"]
9789: Sending request to url-4
[10796, "Response from url-4"]
觀看現場演示: https : //jsbin.com/kakede/4/edit?js,console
處理錯誤
如果我們只是想在任何 HTTP 請求失敗時忽略,我們必須連結 catch()
ofter mockHTTPRequest()
。
function mockHTTPRequest(url) {
if (url == 'url-3') {
return Observable.throw(new Error(`Request ${url} failed.`));
} else {
return Observable.of(`Response from ${url}`)
.delay(1000);
}
}
let urls = ['url-1', 'url-2', 'url-3', 'url-4'];
let start = (new Date()).getTime();
Observable.from(urls)
.concatMap(url => mockHTTPRequest(url).catch(obs => Observable.empty()))
.timestamp()
.map(stamp => [stamp.timestamp - start, stamp.value])
.subscribe(val => console.log(val));
這只是忽略了 url-3
的呼叫:
[1004, "Response from url-1"]
[2012, "Response from url-2"]
[3016, "Response from url-4"]
檢視現場演示: https : //jsbin.com/jowiqo/2/edit?js,console
如果我們沒有使用 catch()
運算子,則 url-3
會導致鏈傳送錯誤通知,並且最後的 url-4
將不會被執行。
檢視現場演示: https : //jsbin.com/docapim/3/edit?js,console