我正在编写一项服务,人们可以在Spotify播放列表中粘贴网址,然后在不同的服务中导出播放列表。对于每个跟踪请求中粘贴的URL,需要对Spotify api进行。
此代码:
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个同时运行的呼叫。 Merge with maxConcurrent设置似乎是Stackoverflow中讨论的完美解决方案。
这看起来像这样:
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 checkin:
答案 0 :(得分:3)
使用spotifyService.lookupTrack
的代码存在的问题是Observable
不会返回Promise
而是Observable
。某些flatMap
函数(如Observable
)将handle Promise
s as well,但Promise
和Observable
之间的区别在于Promise
是懒惰的,虽然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')
);
不是。用户3743222建议,您可以使用Observable.defer
从承诺工厂函数中创建一个惰性可观察对象。这个小例子是用JavaScript而不是TypeScript,因此它可以在这里运行。
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
text-center
答案 1 :(得分:0)
我设法让它按照我想要的方式工作,但我仍然很好奇为什么合并不起作用。 这里构建了唯一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 checkin。