从轮询到WebSocket的使用

53 阅读2分钟

假设以下场景: 世界杯决赛期间,我们要实时的记录双方进球数量(前端展示)。

定期轮询

定期向服务器发送请求,例如每10秒向服务器发送一次请求。

缺点:

  • 对于进球的情况最多会有10s的延迟
  • 频繁的请求消耗性能,不管是否有进球,10s都会向服务器请求一次。

长轮询

  浏览器向服务器发送一次请求获取进球情况,服务器端发现数据并未更新于是就原地静静等待(不对请求做出响应,也不关闭连接),然后突然法国进球了!数据更新了!服务器马上做出对之前请求的响应,然后浏览器同时重新发出一个新的请求等待下一次响应。

客户端代码

async function subscribe() {
  let response = await fetch("/api/xxx/xxx");
  if (response.status == 502) { 
    // 连接超时重新发送请求
    await subscribe();
  } else if (response.status != 200) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    await subscribe();
  } else {
    // 服务器返回内容显示
    let num = await response.text();
    alert(`进球数${num}`);
    // 再次调用 subscribe() 获取下一条消息
    await subscribe();
  }
}

subscribe();

优点

  • 不依靠特定的协议,是和服务器保持长久连接最简单的方式。

缺点

  • 当推送的消息频率很低时长轮询很有效,但是推送较为频繁的时候,每次推送都是一个独立的请求,同样会带来一些性能问题。

Websokct

WebSockets 是一种先进的技术。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此 API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。 ——MDN

一些常用的基于WebSokcet协议的库

  • Socket.IO: 一个基于长轮询/WebSocket 的 Node.js 第三方传输协议。
  • ws: 一个流行的 WebSocket 客户端和服务器 Node.js库。

用ws库写一个简单的🌰

服务端

import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 3000 });

wss.on('connection', function connection(ws) {
   ws.on('message', function message(data) {
       console.log('received: %s', data);  // reveived: Hello!
   });

   ws.send('something');  // 给客户端发送的信息
});

客户端代码

// 打开一个WebSocket:
var ws = new WebSocket('ws://localhost:3000/test');
// 响应onmessage事件:
ws.onmessage = function (msg) {
    console.log(msg.data);  // "something"
};

ws.onopen = function (e) {
   // 给服务器发送一个字符串:
   ws.send('Hello!');
}