是否可以在 web worker 中创建 signalR 流连接
Is it possible to create signalR streaming connection in web worker
我正在使用 Angular 8 和 singalR 从服务器流式传输图像。
我注意到流式传输会减慢我的 UI 渲染速度。
我希望整个流媒体部分转移到 Web Worker,并且只有有价值的内容从 Web Worker 发送到 UI tread。
我没有代码示例,因为我不确定我的想法是否可行。
任何人都可以给我一些提示,或者 post,因为我在其中找不到任何关于网络工作者和网络套接字 (signalR) 连接的信息。
经过一番研究,我终于完成了这个。
这是可能的,有几个提示:
https://angular.io/guide/web-worker
创建 web worker, ng generate webWorker 是用于此的命令,Angular 将为您设置环境。
如果您在没有此命令的情况下执行此操作,则还有其他工作要做。请检查文档。
安装@microsoft/signalr 库,而不是@aspnet/signalr。我在使用 @aspnet/signalr.
在 Web Worker 中建立连接时遇到问题
然后我从我的组件调用 worker 建立连接:
public establishConnectionToStreamingHub() {
if (!this.streamingWorker) {
this.streamingWorker = new Worker('./streaming-data.worker', { type: 'module' });
this.streamingWorker.postMessage(<StreamingWorkerRequest>{
action: StreamingWorkerAction.EstablishConnection,
baseHref: this.href
});
this.streamingWorker.onmessage = this.onWorkerMessage;
}
}
// listen for streaming response from worker.
// I created interface here for message type.
// If message is success I notified listener about it, if message is error handling should be added here.
private onWorkerMessage = (message) => {
const response = message.data as StreamingWorkerResponse;
if (response.type === ResponseMessageType.StreamingSuccessResult) {
this.streamingDataNotify(response.data);
}
}
这是我的流媒体工作文件。
这里的要点是我有一个 class 用于连接和流式传输。
我第一次收到消息给工作人员时,如果消息是 'StreamingWorkerAction.EstablishConnection',我会检查消息类型。
如果是,我创建新的 class 实例并在 class 构造函数中建立到集线器的连接。我也将工人实例发送到 class。
之后它为所有的流请求class对象负责。
import { StreamingWorkerAction,
StreamingWorkerRequest,
StreamingWorkerResponse,
ResponseMessageType
} from './streaming-worker.model';
export class StreamingClass {
private hubConnection: HubConnection;
private workerInstance;
private href = '';
private streamingSubscription: ISubscription<Data>;
constructor(data: StreamingWorkerRequest) {
this.href = data.baseHref;
this.workerInstance = data.workerInstance;
this.connectHub().subscribe(result => {
console.log('Streaming connection established.')
}, error => {
this.workerInstance.postMessage(<StreamingWorkerResponse>{
type: ResponseMessageType.ConnectingError,
error: error
});
});
this.workerInstance.onmessage = (event) => {
const requestData = event.data as StreamingWorkerRequest;
if (requestData.action === StreamingWorkerAction.StartStreaming) {
this.clearCurrentSubscription();
this.streamingSubscription = this.startStreaming(streamingId);
}
};
}
private clearCurrentSubscription() {
if (this.streamingSubscription) {
this.streamingSubscription.dispose();
}
}
private startStreaming(streamingId: string): ISubscription<StreamingData> {
return this.hubConnection.stream<StreamingData>('Stream', streamingId).subscribe({
next: data => {
this.workerInstance.postMessage(<StreamingWorkerResponse>{
type: ResponseMessageType.StreamingSuccessResult,
data: data
});
},
complete: () => {
console.log('complete');
},
error: error => {
this.workerInstance.postMessage(<StreamingWorkerResponse>{
type: ResponseMessageType.StreamingError,
error: error
});
}
});
}
private connectHub(): Observable<boolean> {
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.href + '/api/hub/pathToTheHub')
.withAutomaticReconnect()
.build();
}
}
// web worker event listener
addEventListener('message', event => {
const requestData = event.data as StreamingWorkerRequest;
if (requestData.action === StreamingWorkerAction.EstablishConnection) {
requestData.workerInstance = self;
const streamingClass = new StreamingClass(requestData);
}
});
更新:2020 年 2 月 9 日
@microsoft/signalr 库的 npm 站点上:https://www.npmjs.com/package/@microsoft/signalr
我注意到了这一点:
To use the client in a webworker, copy *.js files from the dist/webworker > >folder to your script folder include on your webworker using the importScripts >function. Note that webworker SignalR hub connection supports only absolute path >to a SignalR hub.
之后我在我的节点模块中找到了 webworker 文件夹:\node_modules@microsoft\signalr\dist\webworker
并将文件 signalr.js 复制到路径上的资产文件夹:assets/scripts/signalr.js.
然后在我的工作文件中,我导入了这样的脚本:
import * as signalR from '../../../../assets/scripts/signalr.js';
并且在 worker 文件中将所有旧的 signalR 导入从 webworker 脚本替换为新的。
例如那些行:
private hubConnection: HubConnection;
private streamingSubscription: ISubscription<MetaModule>;
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.href + '/api/hub/pathToTheHub')
.withAutomaticReconnect()
.build();
改为:
private hubConnection: signalR.HubConnection;
private streamingSubscription: signalR.ISubscription<MetaModule>;
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(this.href + '/api/hub/pathToTheHub')
.withAutomaticReconnect()
.build();
在这些更新之后,我们的流媒体处理速度明显加快。
我正在使用 Angular 8 和 singalR 从服务器流式传输图像。
我注意到流式传输会减慢我的 UI 渲染速度。 我希望整个流媒体部分转移到 Web Worker,并且只有有价值的内容从 Web Worker 发送到 UI tread。
我没有代码示例,因为我不确定我的想法是否可行。
任何人都可以给我一些提示,或者 post,因为我在其中找不到任何关于网络工作者和网络套接字 (signalR) 连接的信息。
经过一番研究,我终于完成了这个。 这是可能的,有几个提示:
https://angular.io/guide/web-worker 创建 web worker, ng generate webWorker 是用于此的命令,Angular 将为您设置环境。 如果您在没有此命令的情况下执行此操作,则还有其他工作要做。请检查文档。
安装@microsoft/signalr 库,而不是@aspnet/signalr。我在使用 @aspnet/signalr.
在 Web Worker 中建立连接时遇到问题然后我从我的组件调用 worker 建立连接:
public establishConnectionToStreamingHub() {
if (!this.streamingWorker) {
this.streamingWorker = new Worker('./streaming-data.worker', { type: 'module' });
this.streamingWorker.postMessage(<StreamingWorkerRequest>{
action: StreamingWorkerAction.EstablishConnection,
baseHref: this.href
});
this.streamingWorker.onmessage = this.onWorkerMessage;
}
}
// listen for streaming response from worker.
// I created interface here for message type.
// If message is success I notified listener about it, if message is error handling should be added here.
private onWorkerMessage = (message) => {
const response = message.data as StreamingWorkerResponse;
if (response.type === ResponseMessageType.StreamingSuccessResult) {
this.streamingDataNotify(response.data);
}
}
这是我的流媒体工作文件。 这里的要点是我有一个 class 用于连接和流式传输。 我第一次收到消息给工作人员时,如果消息是 'StreamingWorkerAction.EstablishConnection',我会检查消息类型。 如果是,我创建新的 class 实例并在 class 构造函数中建立到集线器的连接。我也将工人实例发送到 class。 之后它为所有的流请求class对象负责。
import { StreamingWorkerAction,
StreamingWorkerRequest,
StreamingWorkerResponse,
ResponseMessageType
} from './streaming-worker.model';
export class StreamingClass {
private hubConnection: HubConnection;
private workerInstance;
private href = '';
private streamingSubscription: ISubscription<Data>;
constructor(data: StreamingWorkerRequest) {
this.href = data.baseHref;
this.workerInstance = data.workerInstance;
this.connectHub().subscribe(result => {
console.log('Streaming connection established.')
}, error => {
this.workerInstance.postMessage(<StreamingWorkerResponse>{
type: ResponseMessageType.ConnectingError,
error: error
});
});
this.workerInstance.onmessage = (event) => {
const requestData = event.data as StreamingWorkerRequest;
if (requestData.action === StreamingWorkerAction.StartStreaming) {
this.clearCurrentSubscription();
this.streamingSubscription = this.startStreaming(streamingId);
}
};
}
private clearCurrentSubscription() {
if (this.streamingSubscription) {
this.streamingSubscription.dispose();
}
}
private startStreaming(streamingId: string): ISubscription<StreamingData> {
return this.hubConnection.stream<StreamingData>('Stream', streamingId).subscribe({
next: data => {
this.workerInstance.postMessage(<StreamingWorkerResponse>{
type: ResponseMessageType.StreamingSuccessResult,
data: data
});
},
complete: () => {
console.log('complete');
},
error: error => {
this.workerInstance.postMessage(<StreamingWorkerResponse>{
type: ResponseMessageType.StreamingError,
error: error
});
}
});
}
private connectHub(): Observable<boolean> {
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.href + '/api/hub/pathToTheHub')
.withAutomaticReconnect()
.build();
}
}
// web worker event listener
addEventListener('message', event => {
const requestData = event.data as StreamingWorkerRequest;
if (requestData.action === StreamingWorkerAction.EstablishConnection) {
requestData.workerInstance = self;
const streamingClass = new StreamingClass(requestData);
}
});
更新:2020 年 2 月 9 日
@microsoft/signalr 库的 npm 站点上:https://www.npmjs.com/package/@microsoft/signalr
我注意到了这一点:
To use the client in a webworker, copy *.js files from the dist/webworker > >folder to your script folder include on your webworker using the importScripts >function. Note that webworker SignalR hub connection supports only absolute path >to a SignalR hub.
之后我在我的节点模块中找到了 webworker 文件夹:\node_modules@microsoft\signalr\dist\webworker
并将文件 signalr.js 复制到路径上的资产文件夹:assets/scripts/signalr.js.
然后在我的工作文件中,我导入了这样的脚本:
import * as signalR from '../../../../assets/scripts/signalr.js';
并且在 worker 文件中将所有旧的 signalR 导入从 webworker 脚本替换为新的。 例如那些行:
private hubConnection: HubConnection;
private streamingSubscription: ISubscription<MetaModule>;
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.href + '/api/hub/pathToTheHub')
.withAutomaticReconnect()
.build();
改为:
private hubConnection: signalR.HubConnection;
private streamingSubscription: signalR.ISubscription<MetaModule>;
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(this.href + '/api/hub/pathToTheHub')
.withAutomaticReconnect()
.build();
在这些更新之后,我们的流媒体处理速度明显加快。