[英]Rate limiting http calls made by rxjs
我正在編寫一項服務,人們可以從Spotify播放列表粘貼網址,然后在不同的服務中導出播放列表。 對於每個跟蹤需要在Spotify api中進行請求粘貼的URL。
這段代碼:
Rx.Observable.fromArray<ITrackIdentifier>( this._allTracks )
.pluck<string>( "id" )
.distinct()
.flatMap(
( trackId ) => this.spotifyService.lookupTrack( trackId ).
catch( ( error ) => this.handleError( error ) ))
.subscribe(
( result ) => this.handleTrackLookupResult( result ),
( error ) => this.handleError( error ),
() => this.handleComplete()
);
除了添加大量曲目之外,這實際上工作正常。 我的一個示例播放列表有超過500個曲目,因此立即進行500次調用,瀏覽器需要處理它們/從緩存中返回項目,因此瀏覽器速度很慢並且鎖定並且當我超過api調用限制時,spotify會返回錯誤負載。
我希望能夠只說10個同時運行的呼叫。 與maxConcurrent合並組似乎是完美的解決方案上所討論#1 。
這看起來像這樣:
Rx.Observable.fromArray<ITrackIdentifier>( this._allTracks )
.pluck<string>( "id" )
.distinct()
.map(
( trackId ) => this.spotifyService.lookupTrack( trackId ).
catch( ( error ) => this.handleError( error ) ))
.merge(10)
.subscribe(
( result ) => this.handleTrackLookupResult( result ),
( error ) => this.handleError( error ),
() => this.handleComplete()
);
但它只是不起作用。 在Chrome網絡調試器中,您可以看到所有呼叫同時進行,並且大多數排隊等待多年,直到它們失敗。
為什么這不起作用? 我怎么能解決這個問題呢?
使用merge
的代碼問題是spotifyService.lookupTrack
不返回Observable
而是Promise
。 像flatMap
這樣的一些Observable
函數也會處理Promise
,但是Observable
和Promise
之間的區別在於Observable
是懶惰的,而Promise
則不是。 您可以使用Observable.defer
從promise工廠函數中創建一個惰性observable,如user3743222所示。 這個小例子是用JavaScript而不是TypeScript,因此它可以在這里運行。
console.log = x => {var d = document,b=d.body,p=d.createElement('pre'); p.style.margin = "0"; p.appendChild(d.createTextNode(''+x)); b.appendChild(p); window.scrollTo(0, b.scrollHeight); }; function log_delay(timeout, value) { return new Promise(resolve => { console.log('Start: ' + value); setTimeout(() => { console.log('End: ' + value); resolve(value); }, timeout); }); } Rx.Observable.range(0, 6) .map(x => Rx.Observable.defer( () => log_delay(1000, x) .catch(e => console.log('Inner catch')) )) .merge(2) .subscribe( s => console.log('Result: ' + s), s => console.log('Error: ' + s), s => console.log('Complete') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
我設法讓它按照我想要的方式工作,但我仍然很好奇為什么合並不起作用。 這里構建了唯一ID列表,然后我們使用concatMap為每個id創建一個Observable,然后在移動到下一個項目之前等待一段時間:
Rx.Observable.fromArray<ITrackIdentifier>( this._allTracks )
.pluck<string>( "id" )
.distinct()
.concatMap( ( id, index ) => Rx.Observable.interval( 50 ).take( 1 ).map( () => { return id } ) )
.flatMap(
( trackId ) => this.spotifyService.lookupTrack( trackId ).
catch( ( error ) => this.handleError( error ) ))
.subscribe(
( result ) => this.handleTrackLookupResult( result ),
( error ) => this.handleError( error ),
() => this.handleComplete()
);
在這個例子中,我在每次通話之間等待50ms。 這大大減少了錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.