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});
}