簡體   English   中英

限制rxjs進行的http調用

[英]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()
            );
  1. 從ITrackIdentifiers列表中創建一個observable
  2. 獲取軌道標識符的id以創建可觀察的字符串(ID)
  3. 刪除列表中的任何重復ID
  4. 為每個http spot調用創建一個observable(並捕獲錯誤)
  5. 將所有這些可觀察對象的結果合並到一個帶有flatmap的流中

除了添加大量曲目之外,這實際上工作正常。 我的一個示例播放列表有超過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網絡調試器中,您可以看到所有呼叫同時進行,並且大多數排隊等待多年,直到它們失敗。

為什么這不起作用? 我怎么能解決這個問題呢?

以下是Github在此階段與項目簽到的簽到

使用merge的代碼問題是spotifyService.lookupTrack不返回Observable而是Promise flatMap這樣的一些Observable函數也會處理Promise ,但是ObservablePromise之間的區別在於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。 這大大減少了錯誤。

這是Github在此階段與項目簽到的簽到

暫無
暫無

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

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