• angular5 websocket 商品价格 关注商品价格 在线商品竞拍


    项目简介描述:模拟在在线商品竞拍,单击关注某个商品时,可以在商品详情页上看到实时的看到的别人竞拍的商品价格,模拟从后端实时的获取数据,当

    单击取消按钮时,客户端即取消对服务器端的返回的数据的订阅,并关闭数据流。

    项目流程图:

    项目步骤:

    1. 对点击关注按钮进行编码:

    1 // 模板代码
    2 <div class="thumbnail">
    3   <button class="btn btn-default btn-lg" [class.active]="isWatched" (click)='watchProduct()'>
    4     {{isWatched ? '取消关注':'关注'}}
    5   </button>
    6   <label>最新出价: {{currentBid | number: '.2-2'}}元</label>
    7 </div>

    2. 模板中的ts属性的添加:

    // 关注参数
      public isWatched:boolean = false; // 是否关注,默认是false,即为没有关注某个商品
      public currentBid: number; // 当前商品的价格
    
      // 保存这个流
      public subscription: Subscription; // 当订阅一个流时的返回值,使用它可以取消对某个流的订阅
    
    // 注入WebsocketService, 支持websocket协议,支持双向的通信,即客户端和服务器能同时回复和发送数据
      // 服务需要注入器,此例中的引入的WebsocketService时,可以在constructor快速的实现注入,即可以使用
      constructor(private productService: ProductService, private routeInfo: ActivatedRoute, private wsService: WebsocketService) { }

    3. 作为中介媒体的服务来成为WebSocket的服务的创建流,发送消息的函数:

    // 常见WebSocket对象
    public ws: Websocket;
    
      // 通过url来创建websocket流, 返回可观测的流
      createObservableSocket(url: string, id: number): Observable<any> {
        this.ws = new WebSocket(url); // 创建连接
        return new Observable( // 返回可观测的流
          observer => {
            this.ws.onmessage = (event) => observer.next(event.data); // 推送内容
            this.ws.onerror = (event) => observer.error(event); // 当发生错误时,推送错误消息
            this.ws.onclose = (event) => observer.complete(); // 当关闭时,可观察对象的完毕
            this.ws.onopen = (event) => this.sendMessage({productId: id}); // 当ws打开时,即通过函数sendMessage发送数据
            return () => this.ws.close(); // 这个匿名函数取消订阅的方法的时候调用,关闭WebSocket, 否则的话,容易造成内存的泄露;
          }
        )
      }
    
      // 通过创建的ws对象,来发送数据,发送的数据的格式是字符串的格式
      sendMessage(message: any) {
        this.ws.send(JSON.stringify(message)); // 穿过来的参数是对象,但是send消息的格式是字符串格式的;
      }

    4. 在服务器中实现对productId的存储:

    const Server = require('ws').Server; // 后端创建ws服务器
    // Map中存在的是:每一个客户端关注的商品的id的数组,因为每一个客户端可以关注多个商品;
    const subscriptions = new Map<any, number[]>();
    
    const wsServer = new Server({port: 8090});
    
    wsServer.on('connection', (websocket) => {
      websocket.on('message', (message) => {
          // 当客户端有信息传递时,即服务器端接收,由于这个客户端传递个是JSON.stringify({productId:id});所以在接到数据时,使用
          // JSON.parse(message);   
          let messageObj = JSON.parse(message);
          // key值是连接到服务端的客户端,当subscripitons.get(websocket)的值为undefined,则赋值为空数组;   
          let productIds = subscriptions.get(websocket) || []; 
          // 将新的商品的Id放到值的数组中;将已有的和新建的id组合在一起;
          subscriptions.set(websocket, [...productIds, messageObj.productId]); // [...productIds]: 扩展运算符  
      })  
    })
     1 // 实现消息向客户端的定时的推送
     2 // 模拟数据的更新
     3 setInterval(function() {
     4     // 随机生成每个商品的最新的商品的价格
     5     products.forEach((product) => {
     6       let currentBid = currentBids.get(product.id) || product.price;  
     7       let newBid = currentBid + Math.random() * 5;
     8       currentBids.set(product.id, newBid);           
     9     })
    10     // 循环每一个客户端, 推送每一个客户端关注的商品的价格
    11     subscriptions.forEach((productIds: number[], ws) => {
    12         // 返回的数据的格式是:[{productId:xxx,bid: xxx},{},{}],对应是每个被关注的商品的最新的报价
    13        // *** 防止页面刷新报错;
    14         if (ws.readyState === 1) {
    15         //    通过映射将pid组成{productId: pid, bid: currentBid.get(pid)}
    16             let newBids = productIds.map(pid => ({
    17                 productId: pid,
    18                 bid: currentBids.get(pid)
    19             }));
    20             // 发送的数据
    21             ws.send(JSON.stringify(newBids));
    22         } else {
    23             subscriptions.delete(ws); // 删除已经关闭的客户端
    24         }
    25        // 这之后,然后在客户端订阅这个流;
    26     });
    27 }, 2000);

    5. 客户端对服务器的流的接收(关注)和取消(取消关注):

     1 watchProduct() {
     2     // 服务器返回的流的订阅
     3     if (this.subscription) {
     4       //  取消对流的订阅, 并对subscription赋值为null;
     5      this.subscription.unsubscribe();
     6      this.isWatched = false; // 按钮的状态的变化
     7      this.subscription = null; // 将流的对象置空
     8     } else {
     9       this.isWatched = true; // 按钮的状态的变化
    10       this.subscription = this.wsService.createObservableSocket('ws://localhost:8090', this.product.id)
    11       .subscribe(
    12          products => {
    13             products = JSON.parse(products);
    14             console.log(products);
    15             let product = products.find(p => p.productId == this.product.id); //通过id筛选出当前的商品
    16             this.currentBid = product.bid; // 展示在页面上
    17          }
    18       );
    19     }
    20   }

    6. 重点是websocket的编程的流的创建和订阅,node服务器来模拟用户的访问和出价,对流的数据的处理。

    对websocket的编程的流程有大概的了解。

  • 相关阅读:
    curl 设置超时时间
    allure 2
    shell 给文件每一行都添加指定字符串
    shell 文件的包含
    shell 求数组的平均值,求和,最大值,最小值
    shell 编写进度条
    shell 换行与不换行
    Linux常用命令简述--dirname与basename
    shell中脚本参数传递getopts
    Shell 中eval的用法
  • 原文地址:https://www.cnblogs.com/zhushunli/p/8921707.html
Copyright © 2020-2023  润新知