是否可以在 Web Worker 中创建 signalR 流连接

Mil*_*los 4 javascript web-worker signalr angular

我使用 Angular 8 和 singalR 从服务器进行图像流传输。

我注意到流媒体会减慢我的 UI 渲染速度。我希望整个流媒体部分转移到 Web Worker,并且仅将有价值的内容从 Web Worker 发送到 UI 部分。

我没有代码示例,因为我不确定我的想法是否可行。
任何人都可以给我一些提示或帖子,因为我在其中没有找到有关网络工作人员和网络套接字(signalR)连接的任何信息。

Mil*_*los 9

经过一番研究,我终于完成了这个。这是可能的,并且有一些提示:

  1. https://angular.io/guide/web-worker 创建 Web Worker,ng 生成 webWorker 是该命令,Angular 将为您设置环境。如果您在没有此命令的情况下执行此操作,则需要执行其他工作。请检查文档。

  2. 安装@microsoft/signalr库,而不是@aspnet/signalr。我在网络工作者中与 @aspnet/signalr 建立连接时遇到问题。

  3. 然后从我的组件中调用工作人员来建立连接:

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

Run Code Online (Sandbox Code Playgroud)

这是我的流工作文件。这里的要点是我有一个用于连接和流传输的类。第一次向工作人员收到消息时,我检查消息类型是否为“StreamingWorkerAction.EstablishConnection”。如果是,我创建新的类实例并在类构造函数中建立与集线器的连接。我也将工人实例发送到班级。它对所有流请求之后的类对象负责。

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);
  }
});
Run Code Online (Sandbox Code Playgroud)

更新:2020年2月9日

在 @microsoft/signalr 库的 npm 站点上:https://www.npmjs.com/package/@microsoft/signalr

我注意到这一点:

要在 webworker 中使用客户端,请使用 importScripts > 函数将 *.js 文件从 dist/webworker >> 文件夹复制到 webworker 上包含的脚本文件夹中。请注意,webworker SignalR 集线器连接仅支持到 SignalR 集线器的绝对路径。

之后我在节点模块中找到了 webworker 文件夹: \node_modules@microsoft\signalr\dist\webworker

并将文件 signalr.js 复制到路径上的资产文件夹:assets/scripts/signalr.js。

然后在我的工作文件中我导入了这样的脚本:

import * as signalR from '../../../../assets/scripts/signalr.js';
Run Code Online (Sandbox Code Playgroud)

并在工作文件中将所有旧的 signalR 导入从 webworker 脚本替换为新的。例如这些行:

private hubConnection: HubConnection;  
private streamingSubscription: ISubscription<MetaModule>;

this.hubConnection = new HubConnectionBuilder()
       .withUrl(this.href + '/api/hub/pathToTheHub')
       .withAutomaticReconnect()
       .build();
Run Code Online (Sandbox Code Playgroud)

更改为:

private hubConnection: signalR.HubConnection;
private streamingSubscription: signalR.ISubscription<MetaModule>;

this.hubConnection = new signalR.HubConnectionBuilder()
      .withUrl(this.href + '/api/hub/pathToTheHub')
      .withAutomaticReconnect()
      .build();
Run Code Online (Sandbox Code Playgroud)

在这些更新之后,我们的流媒体处理速度明显加快。