Angular 如何在服务中使用 Websocket?
Angular how to use Websocket inside a service?
是否有可能以某种方式监听服务内的 WebSocket,并通过监听来自套接字的消息然后将更改发送到我的其他组件(例如通过 observables)使该服务“反应式”?
它当然应该适用于不同的 tab/browser 个实例。
正确的模式是什么?如果我在另一个 angular 组件中使用该服务,我是否需要先以某种方式初始化它,或者是否足以在我的组件中导入依赖项,因为服务中没有 ngOnInit
方法?
我可能会在服务构造函数中创建我的套接字侦听器,然后使用可观察对象创建下一个新事件。但是,不确定具体如何。!
是的,可以在服务中监听 WebSocket 并通过 Observables 通知组件收到的消息。
在我看来,这是 Observables 的一个非常自然的用例。
您可以在启动应用程序时打开 websocket 连接,如果它是 root
中提供的服务,您可以在不同组件之间共享相同的服务实例。
这个函数 returns 一个 Observable,它在打开 websocket 连接时通知 WebSocket
的实例
function openSocket$(url: string) {
return new Observable(
(subscriber: Subscriber<WebSocket>): TeardownLogic => {
const conn = new WebSocket(url);
conn.onopen = () => {
subscriber.next(conn);
subscriber.complete();
};
conn.onerror = (err) => {
console.error("Websocket errored while trying to connect", err);
subscriber.error(err);
};
conn.onclose = (ev) => {
console.log("Websocket closed before having emitted any message");
subscriber.complete();
};
}
);
}
这个函数需要一个 WebSocket
的实例作为输入和 returns 一个 Observable 来通知在 websockets 通道上收到的每条消息:
function messages$(socket: WebSocket) {
// if the onmessage property is defined, it means that this websocket is already in use by
// some component which is interested in its message stream
if (socket.onmessage) {
throw new Error(
"Websocket has already a function set to manage the message stream"
);
}
return new Observable(
(subscriber: Subscriber<MessageEvent>): TeardownLogic => {
socket.onmessage = (msg: MessageEvent) => {
subscriber.next(msg);
};
socket.onerror = (err) => {
console.error("Websocket errored while sgreaming messages");
subscriber.error(err);
};
socket.onclose = () => {
console.log("Websocket closed");
subscriber.complete();
};
return () => {
// clean the onmessage callback when the Observable is unsubscribed so that we can safely check
// whether the onmessage callback is null or undefined at the beginning of this function
socket.onmessage = null;
};
}
);
}
您可以查看使用此机制的应用示例 here。
对于 angular's scope/zone 之外的任何图书馆筹集活动,最好的办法是将其纳入 scope/zone。
这样您就不需要考虑与 angular 生命周期事件的任何进一步同步。
我通常在服务中使用 Subject or ReplaySubject 来确保所有组件都能侦听引发的事件。
@Injectable()
export class YourService {
eventType1$ = new Subject()
constructor(private ngZone: NgZone ...
...
socketObject.onEventType1((eventType1) => {
this.ngZone.run(() => {
this.eventType1$.next(eventType1)
});
})
然后您可以从您的组件中正常订阅此服务的 public observable:
yourComponentFunction() {
this.yourService.eventType1$.subscribe((eventType1) => {
// do something with eventType1
})
}
注意:请记得在组件销毁时完成任何订阅,避免常见的memory leak.
是否有可能以某种方式监听服务内的 WebSocket,并通过监听来自套接字的消息然后将更改发送到我的其他组件(例如通过 observables)使该服务“反应式”?
它当然应该适用于不同的 tab/browser 个实例。
正确的模式是什么?如果我在另一个 angular 组件中使用该服务,我是否需要先以某种方式初始化它,或者是否足以在我的组件中导入依赖项,因为服务中没有 ngOnInit
方法?
我可能会在服务构造函数中创建我的套接字侦听器,然后使用可观察对象创建下一个新事件。但是,不确定具体如何。!
是的,可以在服务中监听 WebSocket 并通过 Observables 通知组件收到的消息。
在我看来,这是 Observables 的一个非常自然的用例。
您可以在启动应用程序时打开 websocket 连接,如果它是 root
中提供的服务,您可以在不同组件之间共享相同的服务实例。
这个函数 returns 一个 Observable,它在打开 websocket 连接时通知 WebSocket
的实例
function openSocket$(url: string) {
return new Observable(
(subscriber: Subscriber<WebSocket>): TeardownLogic => {
const conn = new WebSocket(url);
conn.onopen = () => {
subscriber.next(conn);
subscriber.complete();
};
conn.onerror = (err) => {
console.error("Websocket errored while trying to connect", err);
subscriber.error(err);
};
conn.onclose = (ev) => {
console.log("Websocket closed before having emitted any message");
subscriber.complete();
};
}
);
}
这个函数需要一个 WebSocket
的实例作为输入和 returns 一个 Observable 来通知在 websockets 通道上收到的每条消息:
function messages$(socket: WebSocket) {
// if the onmessage property is defined, it means that this websocket is already in use by
// some component which is interested in its message stream
if (socket.onmessage) {
throw new Error(
"Websocket has already a function set to manage the message stream"
);
}
return new Observable(
(subscriber: Subscriber<MessageEvent>): TeardownLogic => {
socket.onmessage = (msg: MessageEvent) => {
subscriber.next(msg);
};
socket.onerror = (err) => {
console.error("Websocket errored while sgreaming messages");
subscriber.error(err);
};
socket.onclose = () => {
console.log("Websocket closed");
subscriber.complete();
};
return () => {
// clean the onmessage callback when the Observable is unsubscribed so that we can safely check
// whether the onmessage callback is null or undefined at the beginning of this function
socket.onmessage = null;
};
}
);
}
您可以查看使用此机制的应用示例 here。
对于 angular's scope/zone 之外的任何图书馆筹集活动,最好的办法是将其纳入 scope/zone。
这样您就不需要考虑与 angular 生命周期事件的任何进一步同步。
我通常在服务中使用 Subject or ReplaySubject 来确保所有组件都能侦听引发的事件。
@Injectable()
export class YourService {
eventType1$ = new Subject()
constructor(private ngZone: NgZone ...
...
socketObject.onEventType1((eventType1) => {
this.ngZone.run(() => {
this.eventType1$.next(eventType1)
});
})
然后您可以从您的组件中正常订阅此服务的 public observable:
yourComponentFunction() {
this.yourService.eventType1$.subscribe((eventType1) => {
// do something with eventType1
})
}
注意:请记得在组件销毁时完成任何订阅,避免常见的memory leak.