webpack与browser-sync热更新原理深度讲解

栏目: 后端 · 发布时间: 8年前

内容简介:webpack与browser-sync热更新原理深度讲解

目录

本文首发于CSDN网站,下面的版本又经过进一步的修订。

开发环境页面热更新早已是主流,我们不光要吃着火锅唱着歌,享受热更新高效率的快感,更要深入下去探求其原理。

要知道,触类则旁通,常见的需求如赛事网页推送比赛结果、网页实时展示投票或点赞数据、在线评论或弹幕、在线聊天室等,都需要借助热更新功能,才能达到实时的端对端的极致体验。

刚好,最近解决 webpack-hot-middleware 热更新延迟问题的过程中,我深入接触了EventSource技术。遂本文由此开篇,进一步讲解 webpack-hot-middlewarebrowser-sync 背后的技术。

webpack-hot-middleware

webpack-hot-middleware 中间件是webpack的一个plugin,通常结合 webpack-dev-middleware 一起使用。借助它可以实现浏览器的无刷新更新(热更新),即webpack里的HMR(Hot Module Replacement)。如何配置请参考 webpack-hot-middleware ,如何理解其相关插件请参考 手把手深入理解 webpack dev middleware 原理與相關 plugins

webpack加入 webpack-hot-middleware 后,内存中的页面将包含HMR相关js,加载页面后,Network栏可以看到如下请求:

webpack与browser-sync热更新原理深度讲解

__webpack_hmr是一个 type 为EventSource的请求, 从 Time 栏可以看出:默认情况下,服务器每十秒推送一条信息到浏览器。

webpack与browser-sync热更新原理深度讲解

如果此时关闭开发服务器,浏览器由于重连机制,将持续抛出类似 GET http://www.test.com/__webpack_hmr 502 (Bad Gateway) 这样的错误。重新启动开发服务器后,重连将会成功,此时便会刷新页面。

以上这些便是我们使用时感受到的最初的印象。当然,停留在使用层面不是我们的目标,接下来我们将跳出该中间件,讲解其所使用到的 EventSource 技术。

EventSource

EventSource 不是一个新鲜的技术,它早就随着H5规范提出了,正式一点应该叫 Server-sent events ,即 SSE

鉴于传统的通过ajax轮训获取服务器信息的技术方案已经过时,我们迫切需要一个高效的节省资源的方式去获取服务器信息,一旦服务器资源有更新,能够及时地通知到客户端,从而实时地反馈到用户界面上。EventSource就是这样的技术,它本质上还是HTTP,通过response流实时推送服务器信息到客户端。

新建一个EventSource对象非常简单。

const es = new EventSource('/message');// /message是服务端支持EventSource的接口

新创建的EventSource对象拥有如下属性:

属性 描述
url(只读) es对象请求的服务器url
readyState(只读) es对象的状态,初始为0,包含CONNECTING (0),OPEN (1),CLOSED (2)三种状态
withCredentials 是否允许带凭证等,默认为false,即不支持发送cookie

服务端实现 /message 接口,需要返回类型为 text/event-stream 的响应头。

var http = require('http');
http.createServer(function(req,res){
  if(req.url === '/message'){
    res.writeHead(200,{
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
    });
    setInterval(function(){
      res.write('data: ' + +new Date() + '\n\n');
    }, 1000);
  }
}).listen(8888);

我们注意到,为了避免缓存,Cache-Control 特别设置成了 no-cache,为了能够发送多个response, Connection被设置成了keep-alive.。发送数据时,请务必保证服务器推送的数据以 data: 开始,以 \n\n 结束,否则推送将会失败(原因就不说了,这是约定的)。

以上,服务器每隔1s主动向客户端发送当前时间戳,为了接受这个信息,客户端需要监听服务器。如下:

es.onmessage = function(e){
  console.log(e.data); // 打印服务器推送的信息
}

如下是消息推送的过程:

webpack与browser-sync热更新原理深度讲解

webpack与browser-sync热更新原理深度讲解

你以为es只能监听message事件吗?并不是,message只是缺省的事件类型。实际上,它可以监听任何指定类型的事件。

es.addEventListener("####", function(e){// 事件类型可以随你定义
  console.log('####:', e.data);
},false);

服务器发送不同类型的事件时,需要指定event字段。

res.write('event: ####\n');
res.write('data: 这是一个自定义的####类型事件\n');
res.write('data: 多个data字段将被解析成一个字段\n\n');

如下所示:

webpack与browser-sync热更新原理深度讲解

可以看到,服务端指定event事件名为”####”后,客户端触发了对应的事件回调,同时服务端设置的多个data字段,客户端使用换行符连接成了一个字符串。

不仅如此,事件流中还可以混合多种事件,请看我们是怎么收到消息的,如下:

webpack与browser-sync热更新原理深度讲解

除此之外,es对象还拥有另外3个方法: onopen()onerror()close() ,请参考如下实现。

es.onopen = function(e){// 链接打开时的回调
  console.log('当前状态readyState:', es.readyState);// open时readyState===1
}
es.onerror = function(e){// 出错时的回调(网络问题,或者服务下线等都有可能导致出错)
  console.log(es.readyState);// 出错时readyState===0
  es.close();// 出错时,chrome浏览器会每隔3秒向服务器重发原请求,直到成功. 因此出错时,可主动断开原连接.
}

使用EventSource技术实时更新网页信息十分高效。实际使用中,我们几乎不用担心兼容性问题,主流浏览器都了支持EventSource,当然,除了掉队的IE系。对于不支持的浏览器,其PolyFill方案请参考 HTML5 Cross Browser Polyfills

CORS

另外,如果需要支持跨域调用,请设置响应头 Access-Control-Allow-Origin': '*'

如需支持发送cookie,请设置响应头 Access-Control-Allow-Origin': req.headers.originAccess-Control-Allow-Credentials:true ,并且创建es对象时,需要明确指定是否发送凭证。如下:

var es = new EventSource('/message', {
  withCredentials: true
}); // 创建时指定配置才是有效的
es.withCredentials = true; // 与ajax不同,这样设置是无效的

以下是主流浏览器对EventSource的CORS的支持:

Firefox Opera Chrome Safari iOS Android
10+ 12+ 26+ 7.0+ 7.0+ 4.4+

nginx配置

既然说到了EventSource,便有必要谈谈遇到的坑,接下来,就说说我遇到的webpack热更新延迟问题。

如我们所知,webpack借助webpack-hot-middleware插件,实现了网页热更新机制,正常情况下,浏览器打开 http://localhost:8080 这样的网页即可开始调试。然而实际开发中,由于远程服务器需要种cookie登录态到特定的域名上等原因,因此本地往往会用nginx做一层反向代理。即把 http://www.test.com 的请求转发到 http://localhost:8080 上(配置过程这里不详述,具体请参考 Ajax知识体系大梳理-ajax调试技巧 )。转发过后,发现热更新便延迟了。

原因是nginx默认开启的buffer机制缓存了服务器推送的片段信息,缓存达到一定的量才会返回响应内容。只要关闭proxy_buffering即可。配置如下所示:

server {
    listen       80;
    server_name  www.test.company.com;
    location / {
        proxy_pass http://localhost:8080;
        proxy_buffering off;
    }
}

至此,EventSource部分便告一段落。学习讲究由浅入深,循序渐进。后面我将重点讲解的 browser-sync 热更新机制,请耐心细读。

browser-sync

开发中使用 browser-sync 插件调试,一个网页里的所有交互动作(包括滚动,输入,点击等等),可以实时地同步到其他所有打开该网页的设备,能够节省大量的手工操作时间,从而带来流畅的开发调试体验。目前 browser-sync 可以结合 GulpGrunt 一起使用,其API请参考: Browsersync API

通过上面的了解,我们知道 EventSouce 的使用是比较便捷的,那为什么 browser-sync 不使用EventSource技术进行代码推送呢?这是因为 browser-sync 插件共做了两件事:

  • 开发更新了一段新的逻辑,服务器实时推送代码改动信息。数据流:服务器 —> 浏览器,使用EventSource技术同样能够实现。
  • 用户操作网页,滚动、输入或点击等,操作信息实时发送给服务器,然后再由服务器将操作同步给其他已打开的网页。数据流:浏览器 —> 服务器 —> 浏览器,该部分功能EventSource技术已无能为力。

以上, browser-sync 使用WebSocket技术达到实时推送代码改动和用户操作两个目的。至于它是如何计算推送内容,根据不同推送内容采取何种响应策略,不在本次讨论范围之内。下面我们将讲解其核心的WebSocket技术。

WebSocket

WebSocket是基于TCP的全双工通讯的协议,它与EventSource有着本质上的不同.(前者基于TCP,后者依然基于HTTP) 该协议于2011年被IETF定为标准RFC6455,后被RFC7936补充. WebSocket api也被W3C定为标准。

WebSocket使用和HTTP相同的TCP端口,默认为80, 统一资源标志符为ws,运行在TLS之上时,默认使用443,统一资源标志符为wss。它通过 101 switch protocol 进行一次TCP握手,即从HTTP协议切换成WebSocket通信协议。

相对于HTTP协议,WebSocket拥有如下优点:

  • 全双工,实时性更强。
  • 相对于http携带完整的头部,WebSocket请求头部明显减少。
  • 保持连接状态,不用再验权了。
  • 二进制支持更强,Websocket定义了二进制帧,处理更轻松。
  • Websocket协议支持扩展,可以自定义的子协议,如 permessage-deflate 扩展。

支持性

优秀技术的落地,调研兼容性是必不可少的环节。所幸的是,现代浏览器对WebSocket的支持比较友好,如下是PC端兼容性:

IE/Edge Firefox Chrome Safari Opera
10+ 11+ 16+ 7+ 12.1+

如下是mobile端兼容性:

iOS Safari Android Android Chrome Android UC QQ Browser Opera Mini
7.1+ 4.4+ 57+ 11.4+ 1.2+ -

Frame

根据RFC6455文档,WebSocket协议基于Frame而非Stream(EventSource是基于Stream的)。因此其传输的数据都是Frame(帧)。想要了解数据的往返,弄懂协议处理过程,Frame的解读是必不可少。如下便是Frame的结构:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R|opcode|M|Payload len|Extended payload length|
|I|S|S|S|(4)|A|(7)|(16/64)|
|N|V|V|V||S||(if payload len==126/127)|
||1|2|3||K|||
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|Extended payload length continued,if payload len == 127|
+ - - - - - - - - - - - - - - - +-------------------------------+
||Masking-key,if MASK set to 1|
+-------------------------------+-------------------------------+
|Masking-key (continued)|Payload Data|
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|Payload Data continued ...|
+---------------------------------------------------------------+

第一个字节包含FIN、RSV、Opcode。

  • FIN:size为1bit,标示是否最后一帧。 %x0 表示还有后续帧, %x1 表示这是最后一帧。

  • RSV1、2、3,每个size都是1bit,默认值都是0,如果没有定义非零值的含义,却出现了非零值,则WebSocket链接将失败。

  • Opcode,size为4bits,表示『payload data』的类型。如果收到未知的opcode,连接将会断开。已定义的opcode值如下:

    %x0:	代表连续的帧
    %x1:	文本帧
    %x2:	二进制帧
    %x3~7:	预留的非控制帧
    %x8:	关闭握手帧
    %x9:	ping帧,后续心跳连接会讲到
    %xA:	pong帧,后续心跳连接会讲到
    %xB~F:	预留的非控制帧
    

第二个字节包含Mask、Payload len。

  • Mask:size为1bit,标示『payload data』是否添加掩码。所有从客户端发送到服务端的帧都会被置为1,如果置1, Masking-key 便会赋值。

    //若server是一个WebSocket服务端实例
    //监听客户端消息
    server.on('message', function(msg, flags){
      console.log('client say: %s', msg);
      console.log('mask value:', flags.masked);// true,进一步佐证了客户端发送到服务端的Mask帧都会被置为1
    });
    //监听客户端pong帧响应
    server.on('pong', function(msg, flags){
      console.log('pong data: %s', msg);
      console.log('mask value:', flags.masked);// true,进一步佐证了客户端发送到服务端的Mask帧都会被置为1
    });
    
  • Payload len:size为7bits,即使是当做无符号整型也只能表示0~127的值,所以它不能表示更大的值,因此规定”Payload data”长度小于或等于125的时候才用来描述数据长度。如果 Payload len==126 ,则使用随后的2bytes(16bits)来存储数据长度。如果 Payload len==127 ,则使用随后的8bytes(64bits)来存储数据长度。

以上,扩展的Payload len可能占据第三至第四个或第三至第十个字节。紧随其后的是”Mask-key”。

  • Mask-key:size为0或4bytes(32bits),默认为0,与前面Mask呼应,从客户端发送到服务端的帧都包含4bytes(32bits)的掩码,一旦掩码被设置,所有接收到的”payload data”都必须与该值以一种算法做异或运算来获取真实值。
  • Payload data:size为”Extension data” 和 “Application data” 的总和,一般”Extension data”数据为空。
  • Extension data:默认为0,如果扩展被定义,扩展必须指定”Extension data”的长度。
  • Application data:占据”Extension data”之后剩余帧的空间。

关于Frame的更多理论介绍不妨读读 学习WebSocket协议—从顶层到底层的实现原理(修订版)

关于Frame的数据帧解析不妨读读 WebSocket(贰) 解析数据帧 及其后续文章。

建立连接

了解了Frame的数据结构后,我们来实际练习下。浏览器上,新建一个ws对象十分简单。如下:

let ws = new WebSocket('ws://127.0.0.1:10103/');// 本地使用10103端口进行测试

新建的WebSocket对象如下所示:

webpack与browser-sync热更新原理深度讲解

这中间包含了一次Websocket握手的过程,我们分两步来理解。

第一步,客户端请求。

webpack与browser-sync热更新原理深度讲解

这是一个GET请求,主要字段如下:

Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key:61x6lFN92sJHgzXzCHfBJQ==
Sec-WebSocket-Version:13

Connection字段指定为Upgrade,表示客户端希望连接升级。

Upgrade字段设置为websocket,表示希望升级至Websocket协议。

Sec-WebSocket-Key字段是随机字符串,服务器根据它来构造一个SHA-1的信息摘要。

Sec-WebSocket-Version表示支持的Websocket版本。RFC6455要求使用的版本是13。

甚至我们可以从请求截图里看出,Origin是 file:// ,而Host是 127.0.0.1:10103 ,明显不是同一个域下,但依然可以请求成功,说明Websocket协议是不受同源策略限制的(同源策略限制的是http协议)。

第二步,服务端响应。

webpack与browser-sync热更新原理深度讲解

Status Code: 101 Switching Protocols 表示Websocket协议通过101状态码进行握手。

Sec-WebSocket-Accept字段是由Sec-WebSocket-Key字段加上特定字符串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,计算SHA-1摘要,然后再base64编码之后生成的. 该操作可避免普通http请求,被误认为Websocket协议。

Sec-WebSocket-Extensions字段表示服务端对Websocket协议的扩展。

以上,WebSocket构造器不止可以传入url,还能传入一个可选的协议名称字符串或数组。

ws = new WebSocket('ws://127.0.0.1:10103/', ['abc','son_protocols']);

服务端实现

等等,我们慢一点,上面好像漏掉了一步,似乎没有提到服务端是怎么实现的。请继续往下看:

先做一些准备。ws是一个nodejs版的WebSocketServer实现。使用 npm install ws 即可安装。

var WebSocketServer = require('ws').Server,
    server = new WebSocketServer({port: 10103});
server.on('connection', function(s){
  s.on('message', function(msg){ //监听客户端消息
    console.log('client say: %s', msg);
  });
  s.send('server ready!');// 连接建立好后,向客户端发送一条消息
});

以上, new WebSocketServer() 创建服务器时如需权限验证,请指定 verifyClient 为验权的函数。

server = new WebSocketServer({
  port: 10103,
  verifyClient: verify
});
functionverify(info){
  console.log(Object.keys(info));// [ 'origin', 'secure', 'req' ]
  console.log(info.orgin);// "file://"
  return true;// 返回true时表示验权通过,否则客户端将抛出"HTTP Authentication failed"错误
}

以上, verifyClient 指定的函数只有一个形参,若为它显式指定两个形参,那么第一个参数同上info,第二个参数将是一个 cb 回调函数。该函数用于显式指定拒绝时的HTTP状态码等,它默认拥有3个形参,依次为:

  • result,布尔值类型,表示是否通过权限验证。
  • code,数值类型,若result值为false时,表示HTTP的错误状态码。
  • name,字符串类型,若result值为false时,表示HTTP状态码的错误信息。
// 若verify定义如下
functionverify(info, cb){
  //一旦拥有第二个形参,如果不调用,默认将通过验权
  cb(false, 401, '权限不够');// 此时表示验权失败,HTTP状态码为401,错误信息为"权限不够"
  return true;// 一旦拥有第二个形参,响应就被cb接管了,返回什么值都不会影响前面的处理结果
}

除了 portverifyClient 设置外,其它设置项及更多API,请参考文档 ws-doc

发送和监听消息

接下来,我们来实现消息收发。如下是客户端发送消息。

ws.onopen = function(e){
  // 可发送字符串,ArrayBuffer 或者 Blob数据
  ws.send('client ready!);
};

客户端监听信息。

ws.onmessage = function(e){
  console.log('server say:', e.data);
};

如下是浏览器的运行截图。

webpack与browser-sync热更新原理深度讲解

消息的内容都在Frames栏,第一条彩色背景的信息是客户端发送的,第二条是服务端发送的。两条消息的长度都是13。

如下是Timing栏,不止是WebSocket,包括EventSource,都有这样的黄色高亮警告。

webpack与browser-sync热更新原理深度讲解

该警告说明:请求还没完成。实际上,直到一方连接close掉,请求才会完成。

关闭连接

说到close,ws的close方法比es的略复杂。

语法: close(short code,string reason);

close默认可传入两个参数。code是数字,表示关闭连接的状态号,默认是1000,即正常关闭。(code取值范围从0到4999,其中有些是保留状态号,正常关闭时只能指定为1000或者3000~4999之间的值,具体请参考 CloseEvent - Web APIs )。reason是UTF-8文本,表示关闭的原因(文本长度需小于或等于123字节)。

由于code 和 reason都有限制,因此该方法可能抛出异常,建议catch下.

try{
  ws.close(1001, 'CLOSE_GOING_AWAY');
}catch(e){
  console.log(e);
}

ws对象还拥有onclose和onerror监听器,分别监听关闭和错误事件。(注:EventSource没有onclose监听)

拥有的属性

ws的readyState属性拥有4个值,比es的readyState的多一个CLOSING的状态。

常量 描述 EventSource(值) WebSocket(值)
CONNECTING 连接未初始化 0 0
OPEN 连接已就绪 1 1
CLOSING 连接正在关闭 - 2
CLOSED 连接已关闭 2 3

另外,除了两种都有的url属性外,WebSocket对象还拥有更多的属性。

属性 描述
binaryType 被传输二进制内容的类型,有blob,arraybuffer两种
bufferedAmount 待传输的数据的长度
extensions 表示服务器选用的扩展
protocol 指的是构造器第二个参数传入的子协议名称

文件上传

以前一直是使用ajax做文件上传,实际上,Websocket上传文件也是一把好刀. 其send方法可以发送String,ArrayBuffer,Blob共三种数据类型,发送二进制文件完全不在话下。

由于各个浏览器对Websocket单次发送的数据有限制,所以我们需要将待上传文件切成片段去发送。如下是实现。

1) html。

<inputtype="file"id="file"/>

2) js。

const ws = new WebSocket('ws://127.0.0.1:10103/');// 连接服务器
const fileSelect = document.getElementById('file');
const size = 1024 * 128;// 分段发送的文件大小(字节)
let curSize, total, file, fileReader;

fileSelect.onchange = function(){
  file = this.files[0];// 选中的待上传文件
  curSize = 0;// 当前已发送的文件大小
  total = file.size;// 文件大小
  ws.send(file.name);// 先发送待上传文件的名称
  fileReader = new FileReader();// 准备读取文件
  fileReader.onload = loadAndSend;
  readFragment();// 读取文件片段
};

functionloadAndSend(){
  if(ws.bufferedAmount > size * 5){// 若发送队列中的数据太多,先等一等
    setTimeout(loadAndSend,4);
    return;
  }
  ws.send(fileReader.result);// 发送本次读取的片段内容
  curSize += size;// 更新已发送文件大小
  curSize < total ? readFragment() : console.log('upload successed!');// 下一步操作
}

functionreadFragment(){
  const blob = file.slice(curSize, curSize + size);// 获取文件指定片段
  fileReader.readAsArrayBuffer(blob);// 读取文件为ArrayBuffer对象
}

3) server(node)。

var WebSocketServer = require('ws').Server,
    server = new WebSocketServer({port: 10103}),// 启动服务器
    fs = require('fs');
server.on('connection', function(wsServer){
  var fileName, i = 0;// 变量定义不可放在全局,因每个连接都不一样,这里才是私有作用域
  server.on('message', function(data, flags){// 监听客户端消息
    if(flags.binary){// 判断是否二进制数据
      var method = i++ ? 'appendFileSync' : 'writeFileSync';
      // 当前目录下写入或者追加写入文件(建议加上try语句捕获可能的错误)
      fs[method]('./' + fileName, data,'utf-8');
    }else{// 非二进制数据则认为是文件名称
      fileName = data;
    }
  });
  wsServer.send('server ready!');// 告知客户端服务器已就绪
});

运行效果如下:

webpack与browser-sync热更新原理深度讲解

上述测试代码中没有过多涉及服务器的存储过程。通常,服务器也会有缓存区上限,如果客户端单次发送的数据量超过服务端缓存区上限,那么服务端也需要多次读取。

心跳连接

生产环境下上传一个文件远比本地测试来得复杂。实际上,从客户端到服务端,中间存在着大量的网络链路,如路由器,防火墙等等。一份文件的上传要经过中间的层层路由转发,过滤。这些中间链路可能会认为一段时间没有数据发送,就自发切断两端的连接。这个时候,由于TCP并不定时检测连接是否中断,而通信的双方又相互没有数据发送,客户端和服务端依然会一厢情愿的信任之前的连接,长此以往,将使得大量的服务端资源被WebSocket连接占用。

正常情况下,TCP的四次挥手完全可以通知两端去释放连接。但是上述这种普遍存在的异常场景,将使得连接的释放成为梦幻。

为此,早在websocket协议实现时,设计者们便提供了一种 Ping/Pong Frame的心跳机制。一端发送Ping Frame,另一端以 Pong Frame响应。这种Frame是一种特殊的数据包,它只包含一些元数据,能够在不影响原通信的情况下维持住连接。

根据规范 RFC 6455 ,Ping Frame包含一个值为9的opcode,它可能携带数据。收到Ping Frame后,Pong Frame必须被作为响应发出。Pong Frame包含一个值为10的opcode,它将包含与Ping Frame中相同的数据。

借助ws包,服务端可以这么来发送Ping Frame。

wsServer.ping();

同时,需要监听客户端响应的pong Frame.

wsServer.on('pong', function(data, flags){
  console.log(data);// ""
  console.log(flags);// { masked: true,binary: true }
});

以上,由于Ping Frame 不带数据,因此作为响应的Pong Frame的data值为空串。遗憾的是,目前浏览器只能被动发送Pong Frame作为响应( Sending websocket ping/pong frame from browser ),无法通过JS API主动向服务端发送Ping Frame。因此对于web服务,可以采取服务端主动ping的方式,来保持住链接。实际应用中,服务端还需要设置心跳的周期,以保证心跳连接可以一直持续。同时,还应该有重发机制,若连续几次没有收到心跳连接的回复,则认为连接已经断开,此时便可以关闭Websocket连接了。

Socket.IO

WebSocket出世已久,很多优秀的大神基于此开发出了各式各样的库。其中 Socket.IO 是一个非常不错的开源WebSocke库,旨在抹平浏览器之间的兼容性问题。它基于Node.js,支持以下方式优雅降级:

  • Websocket
  • Adobe® Flash® Socket
  • AJAX long polling
  • AJAX multipart streaming
  • Forever Iframe
  • JSONP Polling

如何在项目中使用Socket.IO,请参考 第一章 socket.io 简介及使用

小结

EventSource,本质依然是HTTP,它仅提供服务端到客户端的单向文本数据传输,不需要心跳连接,连接断开会持续触发重连。

WebSocket协议,基于TCP协议,它提供双向数据传输,支持二进制,需要心跳连接,连接断开不会重连。

EventSource更轻量和简单,WebSocket支持性更好(因其支持IE10+)。通常来说,使用EventSource能够完成的功能,使用WebSocket一样能够做到,反之却不行,使用时若遇到连接断开或抛错,请及时调用各自的 close 方法主动释放资源。

本问就讨论这么多内容,大家有什么问题或好的想法欢迎在下方参与。

本文作者: louis


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python the Hard Way

Learn Python the Hard Way

Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99

Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具