跳至正文
首页 » 博客 » High Performance Angular Grid with Web Sockets

High Performance Angular Grid with Web Sockets

您可能会遇到将数据实时推送到角网格的要求。要将数据推送到浏览器,您需要一种称为WebSocket的技术。您可以使用NodeJS或ASP.NET SignalR实现。出于本文的目的,我们将使用带有NodeJS的Web套接字。

在本文的前半部分,我们将创建一个API,它将使用Web套接字将数据推送到客户端,在本文的后半部分,我们将创建一个Angular应用程序来使用它。在Angular应用程序中,我们将为Angular Grid使用Ignite UI。但是,您也可以使用简单的HTML表从web socket实时使用数据。在本文中,我们将学习如何在HTML表格以及Ignite Angular数据网格中实时使用来自NodeJS Web Socket的数据。我们将见证这两种方法的性能差异。

您可以了解点燃UI的角度更多。

NodeJS API

让我们从创建NodeJS API开始。创建一个空白文件夹并添加一个名为package.json的文件。在package.json中,添加依赖项

  • 核心-js
  • 快递
  • io

或多或少你的package.json文件应该如下所示:

{"name": "demo1","version": "1.0.0","description": "nodejs web socket demo","main": "server.js","依赖项" {"core-js": "^ 2.4.1","express": "^ 4.16.2","socket.io": "^ 2.0.4"},“脚本”: {"test": "echo \" 错误: 未指定测试 \ "& & exit 1"},"作者" "Dhananjay Kumar""许可证""} 

您可以从任何类型的数据库中提取数据,例如关系数据库,无sql数据库等。然而,为了这篇文章的目的,我将保持简单,并在data.js文件中硬编码数据。这个文件将导出一个JSON数组,我们将使用web套接字和定时器。

在名为data.js的文件夹中添加一个文件,并在其中添加以下代码。

data.js

module.exports = {数据: TradeBlotterCDS()}; 函数TradeBlotterCDS() {返回 [{"TradeId": "1","TradeDate" "11/02/2016"“卖” “卖”"概念" "50000000""优惠券" "500""货币" "欧元""ReferenceEntity": "Linde Aktiengesellschaft","Ticker": "LINDE","ShortName": "Linde AG","交易对手" "MUFJ""MaturityDate" "20/03/2023""有效" "12/02/2016"“男高音”: “7”"标识码": "DI537C""EntityCusip": "D50348","EntityType": "Corp",“司法管辖区” “德国”“部门”: “基础材料”"交易者" "Yael Rich""待定"}//...其他数据行]}

您可以在此处找到包含1200行的数据

从data.js文件,我们返回tradebotter数据。现在在您的项目文件夹中,您应该有两个文件: package.json和data.js

此时,运行命令npm install, 安装package.json文件中提到的所有依赖项。运行命令后,您将在项目文件夹中拥有node_modules文件夹。另外,在项目中添加server.js文件。完成所有这些步骤后,您的项目结构应该具有以下文件和文件夹。

  • js
  • js
  • Node_modules文件夹

在server.js中,我们将首先导入所需的模块,

const express = require( 'express' ),app = express(),server = require( 'http' ).createServer(app);io = require( 'socket.io' )(服务器);timerId = null,套接字 = 设置 ();var tradedata = require( './data' );

导入所需模块后,使用express添加路由,如下所示:

app.us e(express.static(__dirname '/dist' ));

在连接套接字时,我们执行以下任务:

  1. 提取数据
  2. 启动计时器 (我们将讨论这个功能稍后在后)
  3. 在断开事件中删除套接字
io.on( 'connection', socket => { console.log( 'Socket ${ socket.id} added' );localdata = tradedata.data;sockets.add(socket);如果 (!timerId) {startTimer();}socket.on( 'clientdata', data => {console.log (数据);});socket.on( '断开 ',() => {console.log( '删除套接字: '${ socket.id}' );Sockets.Delete (插座);console.log( '剩余套接字: '${ sockets.size} );}); });

接下来我们要实现,函数startTimer() 。在这个函数中,我们使用JavaScript函数setInterval() ,并在每个10毫秒的时间帧内发出数据。

函数startTimer() {timerId = setInterval(() => {如果 (!sockets.size) {clearInterval(timerId);timerId = null;console.log (“ 计时器停止 ”);}updateData();对于 (套接字const s) {s.emit( 'data', { data: localdata });} }, 10);}

我们正在调用一个函数updateData(),它将更新数据。在这个函数中,我们循环遍历本地数据并更新两个属性,优惠券和名义,范围之间的随机数。

函数updateData() {localdata.forEach ((a) => {a.Coupon = getRandomInt(10,500);a.名义 = getRandomInt(1000000,7000000);});} 

我们已经实现了getRandomInit功能,如下所示:

函数getRandomInt(min,max) {min = Math.ceil(min);max = Math.floor(max);返回Math.floor(Math.random() * (max-min)) min;}

通过将所有内容放在一起,sever.js应该具有以下代码

Server.js

const express = require( 'express' ),app = express(),server = require( 'http' ).createServer(app);io = require( 'socket.io' )(服务器);timerId = null,套接字 = 设置 ();var tradedata = require( './data' ); var localdata; app.us e(express.static(__dirname '/dist' )); io.on( 'connection', socket => { console.log( 'Socket ${ socket.id} added' );localdata = tradedata.data;sockets.add(socket);如果 (!timerId) {startTimer();}socket.on( 'clientdata', data => {console.log (数据);});socket.on( '断开 ',() => {console.log( '删除套接字: '${ socket.id}' );Sockets.Delete (插座);console.log( '剩余套接字: '${ sockets.size} );}); }); 函数startTimer() {timerId = setInterval(() => {如果 (!sockets.size) {clearInterval(timerId);timerId = null;console.log (“ 计时器停止 ”);}updateData();对于 (套接字const s) {s.emit( 'data', { data: localdata });} }, 10);} 函数getRandomInt(min,max) {min = Math.ceil(min);max = Math.floor(max);返回Math.floor(Math.random() * (max-min)) min;} 函数updateData() {localdata.forEach ((a) => {a.Coupon = getRandomInt(10,500);a.名义 = getRandomInt(1000000,7000000);});} server.listen(8080);console.log (' 访问浏览器中的http:// localhost:8080' ); 

我们在NodeJS中创建了Web套接字,每10毫秒返回数据块。

创建Angular应用程序

在这一步中,让我们创建Angular应用程序。我们将使用Angular CLI创建一个应用程序,然后为Angular Grid添加Ignite UI。按照下面的文章创建一个Angular应用程序,并在应用程序中为Angular Grid添加Ignite UI。

https://www.infragistics.com/community/blogs/b/infragistics/posts/ 四-简单-步骤-工作-与-点燃-ui-为-角-网格-和-rest-服务

如果您正在关注上述文章,则需要在第三步中进行更改,我们正在创建Angular服务以使用API。

让我们从在Angular项目中安装socket.io-client开始。要执行此操作,请运行npm install,

npm i socket.io-客户端

我们将编写一个Angular服务来创建与NodeJS Web Socket的连接。在app.service.ts中,让我们从导入开始。

 “@ angular/core' 导入 {injected};rxjs/Observable导入 { Observable};rxjs/Observer” 导入 { Observer}; 'rxjs/operators' 导入 { map,catchError}; 'socket.Io-client' 导入 * 作为socketIo; “./interfaces导入 { Socket};

我们已经导入了所需的模块。稍后我们将看到如何在interface.ts文件中定义套接字类型。接下来,让我们创建与Web Socket的连接,并从响应中获取下一个数据。在从web套接字返回下一个数据块之前,我们将其转换为Observable。

getQuotes(): Observable < any >  {这个 .socket = socketIo (' http:// localhost:8080' );这个 .socket.on( 'data', (res) => {这个 .观察者下一个 (res.data);});把这个还给我。createObservable();}  createObservable(): Observable  <  任何  > {返回的Observable< any >(observer => {这个 .观察者 = 观察者;});} 

上面的两个函数,将连接到web套接字,获取数据块,并将其转换为可观察的。将所有内容放在一起,app.service.ts将如下所示:

 “@ angular/core' 导入 {injected};rxjs/Observable导入 { Observable};rxjs/Observer” 导入 { Observer}; 'rxjs/operators' 导入 { map,catchError}; 'socket.Io-client' 导入 * 作为socketIo; “./interfaces导入 { Socket}; @ 可注射 ()AppService导出 { 插座: 插座;观察者: 观察者 < any >; getQuotes(): Observable< any > {这个 .socket = socketIo (' http:// localhost:8080' );这个 .socket.on( 'data', (res) => {这个 .观察者下一个 (res.data);});这个还回去。createObservable();} createObservable(): Observable< any > {返回的Observable< any >(observer => {这个 .观察者 = 观察者;});} 私有handleError (错误) {console.error( '服务器错误:' ,错误);if (error.error instanceof Error) {errMessage = error.message;返回Observable.throw(errMessage);}返回Observable.throw(error | 'Socket.io服务器错误 ');} } 

在服务中,我们使用一种名为Socket的类型。我们在interfaces.ts文件中创建了此类型,如下所示:

导出接口Socket {on(event: string, callback: (data: any) => void );emit(event: string, data: any );} 

现在角服务是准备好了,这将使连接到NodeJS的Web套接字,并从API获取数据作为可观察的。

这是正常的Angular服务,可以以通常的方式在组件中使用。从模块中的importin开始,然后在组件构造函数中注入,如下所示:

构造函数 (私有dataService: AppService) { }

我们可以调用服务方法来获取OnInit生命周期中的数据,

ngOnInit() {这个 .sub = 这个。dataService.getQuotes()。订阅 (quote => {这个 .stockQuote = 报价;console.log( this .stockQuote);});}

把所有的东西放在一起,组件类将如下所示。

 “@ angular/core” 导入 { Component,OnInit,OnDestroy}; “./app.Service导入 { AppService};rxjs/Subscription” 导入 { Subscription}; @ Component({'app-root' 选择器,templateUrl: './app.component.html'})AppComponent导出实现OnInit,OnDestroy { 库存报价: 编号;sub: 订阅;列数: 编号;行数: 个数;selectedTicker: string; 构造函数 (private dataService: AppService) { } ngOnInit() {这个 .sub = 这个。dataService.getQuotes()。订阅 (quote => {这个 .stockQuote = 报价;console.log( this .stockQuote);});}ngOnDestroy() {这个 .sub.unsubscribe();}} 

您可能要注意的一件重要事情是,我们正在取消订阅组件的OnDestroy生命周期钩子中返回的可观察对象。在模板上,只需在表中呈现数据如下:

<  >< tr * ngFor = "let f of stockQuote" >< td > {{ f.TradeId }} </ td >< td > {{ f.TradeDate }} </ td >< td > {{ f.BuySell }} </ td >< td > {{ f.概念}} < td >< td > {{ f.优惠券 }} < td >< td > {{ f.Currency }} </ td >< td > {{ f.ReferenceEntity }} </ td >< td > {{ f.Ticker }} </ td >< td > {{ f.ShortName }} </ td ></ tr ></ table > 

由于我们在正常的HTML表中实时渲染数据,您可能会遇到闪烁和一些性能问题。让我们用用于Angular grid的Ignite UI替换HTML表。

https://www.infragistics.com/products/ ignie-ui-angular/Angular/components/grid.html ,您可以通过四个简单的步骤学习使用Ignite UI for Grid和REST服务, 此处

您可以在Angular应用程序中添加Ignite UI网格,如下所示。我们已经使用数据属性绑定设置igxGrid的数据源,然后手动添加列到网格。

<igx-网格[宽度]="'1172px'"# grid1id="grid1"[·罗惠特]="30"[数据]="股票报价"[height] = "'600px'" [autoGenerate] = "false" ><igx-色谱柱[固定]="true"[可排序]="true"宽度="50px"字段="TradeId"页眉="交易Id"[数据类型]="'数字'"></igx-色谱柱><igx-色谱柱[可排序]="true"宽度="120px"字段="交易日期"页眉="交易日期"数据类型="字符串"></igx-色谱柱><igx-色谱柱宽度="70px"字段="BuySell"页眉="买入卖出"数据类型="字符串"></igx-色谱柱><igx-色谱柱[可排序]="true"[数据类型]="'数字'"宽度="110px"字段="名义上的"页眉="名义上的"></ igx-column ><igx-色谱柱宽度="120px"[可排序]="true"字段="优惠券"页眉="优惠券"数据类型="数字"></igx-色谱柱><igx-色谱柱[可排序]="true"宽度="100px"字段="价格"页眉="价格"数据类型="数字"></ igx-column ><igx-色谱柱宽度="100px"字段="货币"页眉="货币"数据类型="字符串"></igx-色谱柱><igx-色谱柱宽度="350px"字段="ReferenceEntity"页眉="引用实体"数据类型="字符串"></igx-色谱柱><igx-色谱柱[可排序]="true"[固定]="true"宽度="130px"字段="Ticker"页眉="Ticker"数据类型="字符串"></igx-色谱柱><igx-色谱柱宽度="350px"字段="ShortName"页眉="短名称"数据类型="字符串"></igx-色谱柱></ igx-grid > 

在我们创建的网格中,您应该关注的几点:

  1. 默认情况下,在Angular grid的Ignite UI上启用虚拟化。
  2. 通过设置sortable属性,可以启用对特定列的排序。
  3. 通过设置固定属性,可以将列固定到网格的左侧。
  4. 通过设置data属性,可以设置网格的数据源。
  5. 您可以使用 <igx-column/> 手动添加列。
  6. <igx-column/> 的字段和标题用于设置字段属性和列标题。

现在,当您运行应用程序时,您会发现grid正在使用数据实时更新,并且不会闪烁。你会发现网格更新每10毫秒。您应该让网格运行,数据实时更新,如下所示:

这样,您可以在Angular应用程序中使用NodeJS Web Socket API实时推送数据。我希望你觉得这篇文章有用。如果你喜欢这篇文章,请分享。此外,如果您还没有Infragistics Ignite UI for Angular组件签出,请务必这样做!他们有50个基于材质的Angular组件,可帮助您更快地编写web应用程序。</p