Angular使用RxJS,它本質上是一個反應式擴展的javascript實現。這是一個使用可觀察序列組成異步和基於事件的程序的庫,非常適合使用WebSockets。
簡而言之,RxJS允許我們從websocket連接中偵聽新消息,然后在“X”事件發生時執行操作。這方面的一個例子可以是實時聊天應用程序。假設我們有3個人連接到我們的聊天應用程序,其中一個人發送消息。如果我們想在收到消息時在應用程序中執行某些操作,那么我們可以簡單地訂閱“新消息”事件並在觸發事件時處理該事件。
使用WebSocket
在我們的角度應用程序中實現WebSockets的最佳方法是將我們的WebSockets和事件封裝在服務中,然后在我們希望與websocket交互的任何組件中調用該服務。
創建應用程序
使用Angular CLI,通過在命令行中鍵入以下內容來創建新應用程序:
ng new websocket_tutorial
這應該創建一個新的,功能齊全的Angular應用程序,我們將在其中實現基於websocket的服務。為了確保它的工作類型:
ng serve
您應該希望看到服務器在端口4200上成功啟動。如果您在首選的Web瀏覽器中導航到localhost:4200,您應該會看到'app works!' 在瀏覽器中顯示。現在我們已經啟動並運行了我們的基本應用程序,讓我們繼續創建我們的websocket服務。
創建我們的Websocket服務
為了讓我們開始,我們將創建一個非常簡單的服務,該服務將連接到任何給定的URL並返回我們可以在其他服務/組件中訂閱的RxJS主題,以便偵聽來自連接套接字的任何傳入消息。
ng g service websocket
我們需要從新服務頂部的rxjs庫中導入*。這將使我們能夠創造既能觀察又能觀察的主體。這實際上意味着我們的主題將觀察我們的websocket以獲取任何傳入消息,並將這些消息廣播到恰好訂閱此服務的任何組件。
1 import { Injectable } from '@angular/core'; 2 import {Subject, Observer, Observable} from 'rxjs';; 3 4 @Injectable() 5 export class WebsocketService { 6 constructor() { } 7 8 private subject: Rx.Subject<MessageEvent>; 9 10 public connect(url): Rx.Subject<MessageEvent> { 11 if (!this.subject) { 12 this.subject = this.create(url); 13 console.log("Successfully connected: " + url); 14 } 15 return this.subject; 16 } 17 18 private create(url): Rx.Subject<MessageEvent> { 19 let ws = new WebSocket(url); 20 21 let observable = Rx.Observable.create( 22 (obs: Rx.Observer<MessageEvent>) => { 23 ws.onmessage = obs.next.bind(obs); 24 ws.onerror = obs.error.bind(obs); 25 ws.onclose = obs.complete.bind(obs); 26 return ws.close.bind(ws); 27 }) 28 let observer = { 29 next: (data: Object) => { 30 if (ws.readyState === WebSocket.OPEN) { 31 ws.send(JSON.stringify(data)); 32 } 33 } 34 } 35 return Rx.Subject.create(observer, observable); 36 } 37 38 }
接下來我們要做的是創建一個與我們的websockets接口的第二個服務,它將作為一種適配器,它將我們的websocket的輸出調整為我們可以在前端輕松使用的形式。再次使用angular-cli創建此服務:
ng g service chat
這應該在根目錄中創建一個chat.service.ts。在這個文件中,我們想要做這樣的事情:
1 import { Injectable } from '@angular/core'; 2 import { Observable, Subject } from 'rxjs'; 3 import { WebsocketService } from './websocket.service'; 4 5 const CHAT_URL = 'ws://echo.websocket.org/'; 6 7 export interface Message { 8 author: string, 9 message: string 10 } 11 12 @Injectable() 13 export class ChatService { 14 public messages: Subject<Message>; 15 16 constructor(wsService: WebsocketService) { 17 this.messages = <Subject<Message>>wsService 18 .connect(CHAT_URL) 19 .pipe(map((response: MessageEvent): Message => { 20 let data = JSON.parse(response.data); 21 return { 22 author: data.author, 23 message: data.message 24 } 25 })); 26 } 27 }
如果是6.0以上的rxjs版本,map函數可以直接使用,代碼如下:
1 this.messages = <Subject<Message>>wsService 2 .connect(CHAT_URL) 3 .map((response: MessageEvent): Message => { 4 let data = JSON.parse(response.data); 5 return { 6 author: data.author, 7 message: data.message 8 } 9 });
更新我們的應用組件
最后,我們要更新我們的app.component.ts文件,以便它導入我們新創建的聊天服務,並允許我們將消息推送到此websocket:
1 import { Component } from '@angular/core'; 2 import { WebsocketService } from './websocket.service'; 3 import { ChatService } from './chat.service'; 4 5 @Component({ 6 selector: 'app-root', 7 templateUrl: './app.component.html', 8 styleUrls: ['./app.component.css'], 9 providers: [ WebsocketService, ChatService ] 10 }) 11 export class AppComponent { 12 13 constructor(private chatService: ChatService) { 14 chatService.messages.subscribe(msg => { 15 console.log("Response from websocket: " + msg); 16 }); 17 } 18 19 private message = { 20 author: 'tutorialedge', 21 message: 'this is a test message' 22 } 23 24 sendMsg() { 25 console.log('new message from client to websocket: ', this.message); 26 this.chatService.messages.next(this.message); 27 this.message.message = ''; 28 } 29 30 }
最后,我們需要更新我們的app組件的html頁面,以便我們可以實際使用我們在組件文件中定義的sendMsg()函數:
<!-- app.component.html -->
1 <h1> 2 Angular6 WebSocket 教程 3 </h1> 4 5 <button (click)="sendMsg()">發送消息</button>
完成這些更改后,通過轉到根目錄並輸入以下命令來提供應用程序:
ng serve
您應該在瀏覽器中看到 "Angula6 WebSocket 教程" 和 “發送消息” 按鈕。
打開控制台並單擊按鈕幾次,您應該看到您的應用程序向測試websocket服務器發送和接收消息。