我正在构建一个记录器对象,该对象异步获取IP地址,然后使用该IP地址记录所有值。它必须在实例化之前就开始收集日志,但是只有在获得IP地址之后才发出日志。然后它应该会正常发光。
这是我的课程:
class LoggerService {
constructor() {
let thisIp;
const getIp = Observable.create(function(observer) {
// doing it with a timeout to emulate bad network
setTimeout(() => {
fetch('https://api.ipify.org?format=json').then(response => response.json()).then(response => {
thisIp = response.ip;
console.log('fetched IP: ', thisIp);
observer.next(response.ip);
observer.complete();
});
}, 5000)
});
// this is where I plan to buffer logs until IP is obtained
this.logStream = new Subject().pipe(buffer(getIp));
// for starters - just log to the console with the IP address
this.logStream.subscribe((value) => console.log(thisIp, value));
}
emit = (message) => this.logStream.next(message);
}
但是它不能按我的需要工作;它确实将所有缓冲的值作为数组输出,但是在获得IP后停止发出它们:
const logger = new LoggerService();
setInterval(() => {
logger.emit('Hey ' + Math.random())
}, 1000);
// I get five messages and that's it
即使缓冲后,如何使它发出我的值?
答案 0 :(得分:1)
您不需要“缓冲”本身的值,而是可以创建一个依赖于异步ipAddress$
的流,因此只有在发出ip地址后,该值才会被发出。 。 combineLatest
可以很好地达到此目的。
让我们为LoggerService
提供一个称为message$
的消息流和一个简单的log()
方法,该方法将提供的字符串推入该流。
我们可以构造一个messagesWithIpAddresses$
流,该流使用combineLatest
创建一个可观察对象,该对象与ipAddress$
一起发出所提供的消息,但前提是两者都已经发出一个值。 / p>
export class LoggerService {
private messages$ = new Subject<string>();
public log(message: string): void {
this.messages$.next(message);
}
constructor(service: GenericService) {
const messagesWithIpAddresses$ = this.messages$.pipe(
mergeMap(message => combineLatest(service.ipAddress$, of(message)))
);
messagesWithIpAddresses$.subscribe(
([ip, message]) => {
// actual logging logic would go here...
console.log(`[${ip}] ${message}`);
}
);
}
}
由于of(message)
将立即发出,因此我们仅在等待ipAddress$
。但是,如果已经发出一个值,那么它也将是即时的。
查看此有效的StackBlitz
答案 1 :(得分:0)
更新:以下答案无效。查看buffer documentation之后 您的记录器Subject()仍然不会发出任何消息,因为它仅在getIp触发时才触发。在您的代码中,在http请求之后,getIp仅触发一次。
我认为我们需要您想要实现的目标的更多细节,以便提出正确的rxjs管道。
我将删除此行
observer.complete(); // remove it
这表明下标流已结束,这就是为什么您不再收到任何消息的原因了。