我是Angular 4.3的新手。我有一个地图应用程序,用于呈现"地图图层"通过下载一系列小图像(" tile")。在启动时,地图图层可能需要0.1到5.0秒才能下载。
当客户端收到两个或多个磁贴时,我需要触发一个事件。我以为我可以通过订阅一个Observable来实现这个目标,它可以在200ms的间隔内重试30次。
到目前为止:
public updateTileContainer() {
this._getTileContainer().subscribe(container => {
if (container) {
console.log('* do stuff with container *');
}
});
}
private _getTileContainer(): Observable<any> {
return Observable.interval(200)
.mergeMap(function (n) {
const tileImages = $('#mymap').find('img[src*=\'kml\']');
console.log(`Retry ${n}: ${tileImages.length} tiles found`);
if (!tileImages || tileImages.length < 2) {
return Observable.of(null);
}
const tileContainer = getContainer(tileImages);
return Observable.of(tileContainer);
})
.take(30);
}
这个有效!有点。我得到了这个输出:
Retry 0: 0 tiles found
Retry 1: 0 tiles found
Retry 2: 0 tiles found
Retry 3: 0 tiles found
Retry 4: 0 tiles found
Retry 5: 0 tiles found
Retry 6: 0 tiles found
Retry 7: 2 tiles found
* do stuff with container *
Retry 8: 3 tiles found
* do stuff with container *
Retry 9: 9 tiles found
* do stuff with container *
Retry 10: 12 tiles found
* do stuff with container *
etc.
我实际上要做的是发出一个事件,在&#34;重试7&#34;,然后停止发射。
如何更改为&#34;完成&#34;我一找到容器就会观察到Observable?我怎样才能跳过&#34;为重试0到6发出事件,因为它们不是真正的事件?如果在没有找到容器的情况下进行30次重试,我可以从Observable中抛出错误吗?
答案 0 :(得分:3)
.retry(count)
如果您的选择中的图块少于2个,则可以抛出错误。然后retry()
30次。
NB:在第30次重试后,实际会发出错误,您需要处理它。但这可能是一件好事(见进一步说明)。
public updateTileContainer() {
this._getTileContainer().subscribe(container => {
console.log('* do stuff with container *');
},error=>{
console.log('no container found !');
});
}
private _getTileContainer(): Observable <any> {
return Observable.timer(200).map(()=>{
const tileImages = $('#googlemap').find('img[src*=\'kml\']');
if (tileImages.length <= 2)
throw new Error("not enough tiles !");
return getContainer(tileImages);
})
.retry(30);
}
您的解决方案和@JonStødle的工作正常。但请注意,如果您无法获得任何容器,则不会收到通知。实际上,如果找不到容器,Observable就完成了,没有错误。
如果您想知道您无法找到容器,处理错误可能是一件好事。
答案 1 :(得分:2)
与编程中的大多数事情一样,有多种方法可以实现相同的结果 - 它主要归结为偏好。
这是我的解决方案。我个人觉得它更具可读性:
private _getTileContainer(): Observable<any> {
return Observable.interval(200)
.map(_ => $('#googlemap').find('img[src*=\'kml\']')) // 1
.take(30) // 2
.skipWhile(tiles = tiles.length < 2) // 3
.map(tiles => getContainer(tiles)) // 4
.take(1); // 5
}
答案 2 :(得分:0)
这给了我我需要的东西,但我不确定是否有更好的方法
public updateTileContainer() {
this._getTileContainer().subscribe(container => {
console.log('* do stuff with container *');
});
}
private _getTileContainer(): Observable<any> {
return Observable.interval(200)
.concatMap(n => {
let tileContainer: any = null;
const tileImages = $('#googlemap').find('img[src*=\'kml\']');
if (tileImages.length >= 2) {
tileContainer = getContainer(tileImages);
}
return Observable.of(tileContainer);
})
.take(30)
.filter(res => res !== null)
.take(1);
}
因此,继原始示例之后,主Observable为前6或7次重试发出nulls
,但filter()
阻止它们传递给订阅者。 take(30)
在30次重试后停止主Observable,而take(1)
后filter()
在第一次非null 重试后停止Observable。
答案 3 :(得分:0)
在rxjs版本6.3.3上工作
import { map, catchError, retryWhen, take, delay, concat } from 'rxjs/operators';
import { throwError } from 'rxjs';
export class ApiEXT {
static get apiURL(): string { return 'http://localhost:57886/api'; };
static httpCLIENT: HttpClient;
static POST(postOBJ: any, retryCOUNT: number = 0, retryITNERVAL: number = 1000) {
return this.httpCLIENT
.post(this.apiURL, JSON.stringify(postOBJ))
.pipe(
map(this.handleSUCCESS),
retryWhen(errors => errors.pipe(delay(retryITNERVAL), take(retryCOUNT), concat(throwError("Giving up Retry.!")))),
catchError(this.handleERROR));
}
private static handleSUCCESS(json_response: string): any {
//TODO: cast_and_return
return JSON.parse(json_response);
}
private static handleERROR(error: Response) {
let errorMSG: string;
switch (error.status) {
case -1: errorMSG = "(" + error.status + "/" + error.statusText + ")" + " Server Not Reachable.!"; break;
default: errorMSG = "(" + error.status + "/" + error.statusText + ")" + " Unknown Error while connecting with server.!"; break;
}
console.error(errorMSG);
return throwError(errorMSG);
}
}