Angular 角度rxjs可观察到以找到第一个活动服务器
我想实现一些插件Angular 角度rxjs可观察到以找到第一个活动服务器,angular,rxjs,observable,Angular,Rxjs,Observable,我想实现一些插件promiseAny所允许的东西,但要实现可观察性,首先得到响应的是“获胜者”。专门用于不同可能服务器的http.get()s 我有以下内容,但是它会将表示http.get的所有合并观察结果返回给每个服务器。其中一台服务器还活着,而我知道的一台已经死了。然而,从订阅返回的值有两个值,并且结果并不表示一个值向上,另一个值向下。订阅(http.get())似乎没有启动。我该怎么写 这是针对Angular 7.2的 import {merge} from 'rxjs'; import
promiseAny
所允许的东西,但要实现可观察性,首先得到响应的是“获胜者”。专门用于不同可能服务器的http.get()s
我有以下内容,但是它会将表示http.get
的所有合并观察结果返回给每个服务器。其中一台服务器还活着,而我知道的一台已经死了。然而,从订阅返回的值有两个值,并且结果并不表示一个值向上,另一个值向下。订阅(http.get()
)似乎没有启动。我该怎么写
这是针对Angular 7.2的
import {merge} from 'rxjs';
import {take} from 'rxjs/operators';
async getActiveServer(servers: string[]): Promise<string> {
return new Promise(async (resolve, reject) => {
merge(this.buildObservables(servers)).pipe(take(1))
.subscribe((value) => {
// .flatMap((value) => {
console.log(`observable - value: ${JSON.stringify(value, null, 2)}`);
if (Array.isArray(value) && value.length > 0) {
resolve(this.findServer(value[0]));
} else {
reject('cannot find server as response is not an array - it is: ${value}');
}
}, (error) => {
console.log(`observable - error: ${error}`);
});
});
private async buildObservables(servers: string[]): Promise<any> {
const observablesBatch = [];
for (const server of servers) {
observablesBatch.push(this.http.get<any>(server + '/health/alive?server=' + server));
}
return observablesBatch;
}
正如您所看到的,我尝试了一个flatMap()
,但在分配给它的时间内没有起作用
我该怎么写
1.我根据@Phix的答案提供了一个有效的答案。 2.编辑-使用@Adrian Brand建议的
race
解决方案。
我喜欢它(如果它起作用的话),但它不起作用。我没有时间来解决这个问题,根据阿德里安的链接帖子,这应该行得通。我得到的语法错误是MonoTypeOperatorFunction上不存在属性subscribe
这不起作用,但如果真的起作用就好了(尽管需要添加过滤或类似功能)
异步getActiveServer(服务器:字符串[]):承诺{
返回新承诺(异步(解析、拒绝)=>{
race(…this.buildObservables(服务器))
.订阅(r=>{
log('找到一个活动服务器:',r);
决心(r.live);
},()=>console.warn('没有任何活动');
});
}
您是否尝试过改用race
我想这就是你所追求的方向。我最初认为
race
可能有效,但这将返回任何首先解决的问题,包括错误
从'rxjs'导入{merge,of,race};
从“rxjs/operators”导入{first,filter,catchError};
//合并所有http请求
合并(…buildObservables())
.烟斗(
//只有那些具有良好响应代码的才能通过
过滤器((服务器:任意)=>server.response<400),
//就拿第一个吧
第一个(),
)
.subscribe(r=>console.log('find a live server:',r),()=>console.warn('Nothing is live'))
//生成模拟服务器响应
函数buildObservables(){
常量响应=[];
for(设i=0;i<4;i++){
推送(mockResponse)(`http://sub${i}.example.com/api/v1`);
}
回应;
}
函数mockResponse(url:string){
const timeout=Math.round(Math.random()*3000)
返回新承诺((解决、拒绝)=>{
设置超时(()=>{
if(Math.random()<.5){
决心({
服务器:url,
答复:200
})
}否则{
拒绝({
服务器:url,
答复:500
})
}
},超时)
})
}
以下是一个基于@Phix的答案的有效方法(请确保对其进行投票):
您可以使用筛选器静态运算符创建raceWithFilter:
函数raceWithFilter(可观测项:可观测输入[],谓词:(值:T)=>布尔值):可观测{
const结果:Observable[]=observables.map(x=>from(x).pipe(map(y=>[y,谓词(y)]));
const none$=zip(…results).pipe(过滤器(x=>x.every(y=>!y[1])),map(()=>null));
const race$=race(results.map(x=>concat(x.pipe(filter(y=>y[1])),NEVER)).pipe(map(x=>x[0]);
返回合并(race$,none$);
}
非常感谢,您提供的主要解决方案是使用…this.buildObservables(服务器)
。我喜欢使用过滤器。我想我应该使用takeUntil(server=>server.response<400)
。我只是尝试了一下,但我不能把它放在合适的位置,因为它会收到不同的论点(我不打算推进这一点,因为我有一个有效的解决方案)。再次感谢!根据您的回答,我提供了一个完整的解决方案作为答案。这看起来可能更简洁。但是,通过以下操作,我在subscribe
上得到一个语法错误,即race正在返回一个MonoTypeOperatorFunction
,而它没有subscribe
方法。我会把我试过的东西贴到我的问题上。谢谢你花时间把它塑造得更接近原始问题!我总是试着在眼睛上打点,然后穿过球座。
observable - value: [
{
"_isScalar": false,
"source": {
"_isScalar": false,
"source": {
"_isScalar": false,
"source": {
"_isScalar": true,
"value": {
"url": "http://localhost:8080/health/alive?server=http://localhost:8080",
"body": null,
"reportProgress": false,
"withCredentials": false,
"responseType": "json",
"method": "GET",
"headers": {
"normalizedNames": {},
"lazyUpdate": null,
"headers": {}
},
"params": {
"updates": null,
"cloneFrom": null,
"encoder": {},
"map": null
},
"urlWithParams": "http://localhost:8080/health/alive?server=http://localhost:8080"
}
},
"operator": {
"concurrent": 1
}
},
"operator": {}
},
"operator": {}
},
{
"_isScalar": false,
"source": {
"_isScalar": false,
"source": {
"_isScalar": false,
"source": {
"_isScalar": true,
"value": {
"url": "https://remoteServer.net//health/alive?server=https://remoteServer.net/",
"body": null,
"reportProgress": false,
"withCredentials": false,
"responseType": "json",
"method": "GET",
"headers": {
"normalizedNames": {},
"lazyUpdate": null,
"headers": {}
},
"params": {
"updates": null,
"cloneFrom": null,
"encoder": {},
"map": null
},
"urlWithParams": "https://remoteserver.net//health/alive?server=https://remoteserver.net/"
}
},
"operator": {
"concurrent": 1
}
},
"operator": {}
},
"operator": {}
}
]
async getActiveServer(servers: string[]): Promise<string> {
return new Promise(async (resolve, reject) => {
race(...this.buildObservables(servers))
.subscribe(r => {
console.log('Found a live server:', r);
resolve(r.alive);
}, () => console.warn('Nothing is alive.'));
});
}
async getActiveServer(servers: string[]): Promise<string> {
return new Promise(async (resolve, reject) => {
merge(...this.buildObservables(servers))
.pipe(
filter((server: any) => server.hasOwnProperty('alive')),
first()
)
.subscribe(r => {
console.log('Found a live server:', r);
resolve(r.alive);
}, () => console.warn('Nothing is alive.'));
});
}
private buildObservables(servers: string[]): Observable<any>[] {
const observablesBatch: Observable<any>[] = [];
for (const server of servers) {
observablesBatch.push(this.http.get<any>(server + '/health/alive?server=' + server));
}
return observablesBatch;
}
async alive(server): Promise<any> {
return Promise.resolve({alive: server});
}