原理
- 客户端发送一个请求,服务器会hold住这个请求;
- 直到监听的内容有改变,才会返回数据,断开连接(或者在一定的时间内,请求还得不到返回,就会因为超时自动断开连接);
- 客户端继续发送请求,重复以上步骤。
长轮询是基于短轮询上的改进版本:主要是减少了客户端发起Http连接的开销,改成了在服务器端主动地去判断所关心的内容是否变化。
所以其实轮询的本质并没有多大变化,变化的点在于:
- 对于内容变化的轮询由客户端改成了服务器端(客户端会在连接中断之后,会再次发送请求,对比短轮询来说,大大减少了发起连接的次数);
- 客户端只会在数据改变时去作相应的改变,对比短轮询来说,并不是全盘接收。
客户端实现
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<div id="clock"></div>
</body>
<script>
let clock = document.getElementById('clock')
function send() {
let xhr = new XMLHttpRequest;
xhr.open('get','/clock',true)
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
clock.innerText = xhr.responseText
// 服务器响应之后,在发送第二次请求
send()
}
}
xhr.send()
}
send()
</script>
</body>
</html>
服务端实现
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
let $timer = setInterval(
() => {
let date = new Date()
let seconds = date.getSeconds()
if (seconds % 5 == 0) {
//需要满足一些条件下,才会进行数据的返回
res.send(date.toLocaleString())
clearInterval($timer) // 清除定时器
}
}, 1000);
}
);
module.exports = router;
效果图
参考代码:GitHub - liu-zq/LongPollingExamples
基于iframe的长轮询模式
这是长轮询技术的另一个种实现方案。
原理
- 在页面中嵌入一个iframe,地址指向轮询的服务器地址,然后在父页面中放置一个执行函数,比如execute(data);
- 当服务器有内容改变时,会向iframe发送一个脚本;
- 通过发送的脚本,主动执行父页面中的方法,达到推送的效果。