长轮询的定义:
1、长轮询是传统轮询(短轮询)的一个翻版,即浏览器定时向服务器发送请求,看看有没有数据更新
2、页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。
长轮询和短轮询的相同点:浏览器都要在接收数据之前,先发起对服务器的连接
长轮询和短轮询的不同点:最大的区别在于服务器如何发送数据
短轮询是服务器立即发送响应,无论数据是否有效
长轮询是等待发送响应。
在前端和后台都会有个超时设置
在前端超时的话,浏览器又会向服务器发起一个请求。
在后台超时的话,服务器会向浏览器发送超时信息。
使用ajax技术,使服务器端和客户端之间建立连接,客户端发送请求,服务器端隔一定时间检查数据库是否有变动,没有变动,返回给客户端的数据为空,即可以是data='',还可能有个提示信息的返回变量msg='超时'。当检查到数据变动了,则服务器端返回数据,data='数据',msg='成功',客户端则做相应处理,处理完立即再次调用函数,与服务器端保持连接;服务器端会设定一定的时间,当超过这个时间数据库没有变化,就向客户端返回超时的信息,让客户端做处理,然后在建立连接关系。无论成功还是失败,都要在此次进行长轮询。
下面这个例子是轮询红包的状态变化:status=0,显示倒计时;status=1,处于抢红包状态;status=2,如果还有下一轮红包活动,则提示还有下一轮红包活动;如果没有下一轮抢红包活动,则显示活动已经结束。一进来该页面,就要显示相应状态的界面信息,然后处理当前有效的红包,才进入长轮询函数。
思路如下:
1、设置变量:
current_redbag用于存储当前有效的红包活动信息,redbags存储所有红包活动信息。
2、函数requestRedbags(activity_id)的作用是根据活动的id号,前端向后台请求该活动的红包信息,并将请求到的红 包信息全部保存在全局变量redbags里面。
3、函数getAvailableRedbag()获取当前有效的红包,若没有有效的红包,则返回null
4、函数handleRedbag(redbag),处理当前有效的红包,即根据当前有效红包的status来进行相应的处理
5、函数check_redbag_status(redBagId,oldStatus,timeOut,startTime) 是检查红包状态变化的长轮询,参数redBagId 是当前该轮红包的id,oldStatus是上次红包的状态,timeOut超时的时间,startTime是开始摇红包开始的时间, 用 于倒计时的。无论成功还是失败,都要在此次进行长轮询
$(function() {
var SHAKE_THRESHOLD = 1800;
var last_update = 0;
var x = y = z = last_x = last_y = last_z = 0;
var num = 0;
var shake_status = 0; //0:未开始,1:正在进行 2:已结束
var activity_id = "96";
var current_redbag;
var redbags;
var time_distance = 0;//本地时间和服务器时间的差
var numMax = 30;
// 请求红包列表,并对数据进行处理
requestRedbags(activity_id);
// --检测设备是否有摇一摇动作
function deviceMotionHandler(eventData) {
var acceleration = eventData.accelerationIncludingGravity;
var curTime = new Date().getTime();
shake_status = 1;
if ((curTime - last_update) > 100) {
var diffTime = curTime - last_update;
last_update = curTime;
x = acceleration.x;
y = acceleration.y;
z = acceleration.z;
var speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
if (speed > SHAKE_THRESHOLD) {
// times++;
handelShakingMotion();
}
last_x = x;
last_y = y;
last_z = z;
}
}
// 设备有摇一摇动作,则对页面已摇次数进行加1,若已经摇到最大次数numMax,则请求抢红包接口
function handelShakingMotion() {
if (shake_status == 2 || shake_status == 0) {
return false;
}
num++;
// 添加摇一摇的声音
$('#shakingAudio').trigger('play');
document.getElementById("numberCount").innerHTML = num;
// setTimeout(function() {
// times = 0;
if (num == numMax) {
num = 0;
shake_status = 2;
// 关闭摇一摇的接口
window.removeEventListener("devicemotion", deviceMotionHandler);
// 添加摇到红包的声音
$('#shakingResult').trigger('play');
// 摇一摇结束之后,请求抢红包接口
drawRedbag(openid);
}
// }, 100); //测试得知80是比较理想的数值
}
// 发送抢红包请求
function drawRedbag(openid){
console.log("drawRedbag");
var url = globalConfig.pre_api_url + "/wxwall_api/redbag/draw_redbag.php";
var param = {
"openid":openid
};
request(url,param,function(response){
// 请求抢红包接口成功
var redBagData = response.data;
// $('#shakingResult').trigger('play');
price = redBagData.price;
refreshView(current_redbag,true);
console.log(response.msg);
});
}
// 抢红包进行中,监听摇一摇的动作
function listenPhoneShake() {
if (window.DeviceMotionEvent) {
window.addEventListener('devicemotion', deviceMotionHandler,false);
console.log("addEventListener devicemotion");
} else {
alert('抱歉,你的手机配置实在有些过不去,考虑换个新的再来试试吧');
}
}
// 当前红包:刷新界面
function refreshView(redbag,is_show_redbag){
// 显示没有红包
if( redbag === undefined ){
$('#shake_view').hide();
$('#countdown').hide();
$('#redBagInfo').hide();
$('#nextRedBagActivity').hide();
$('#activityEnd').hide();
$('#redbagRecordPage').hide();
$('#noRushRedbag').hide();
$('#noData').show();
return;
}
// 有红包,但都已经无效了
if (redbag === null) {
$('#shake_view').hide();
$('#countdown').hide();
$('#redBagInfo').hide();
$('#nextRedBagActivity').hide();
$('#activityEnd').hide();
$('#noData').hide();
// 显示红包记录/或者没有抢到红包
getRedbagRecord();
// $('#redbagRecordPage').show();
return;
}
var status = redbag.status;
if (status == '0') {
//显示倒计时
$("#shake_view").hide();
$('#redBagInfo').hide();
$('#nextRedBagActivity').hide();
$('#activityEnd').hide();
$("#countdown").show();
}else if (status == '1'){
if (is_show_redbag == true) {
$('#hostName').text( activity_title + "的红包" );
$('#fee').text('成功抢到' + price +'元');
$('#shake_view').hide();
$('#nextRedBagActivity').hide();
$('#activityEnd').hide();
$("#countdown").hide();
$('#redBagInfo').show();
return;
}else{
//显示摇一摇
$("#countdown").hide();
$('#redBagInfo').hide();
$('#nextRedBagActivity').hide();
$('#activityEnd').hide();
$('#redBagInfo').hide();
$("#shake_view").show();
}
}else if(status == '2'){
// 判断是否还有下一轮红包,在用户没有抢到红包的情况下,
// 有下一轮红包就显示进入下一轮,没有的话就显示活动结束
// 当用户抢到红包,就不会进入这种情况
var nextRedbag = getAvailableRedbag();
if (nextRedbag == null) {
//若无,显示已经结束;.......
$('#redBagInfo').hide();
$("#shake_view").hide();
$("#countdown").hide();
$('#nextRedBagActivity').hide();
if( price == 0 ){
$('#endActivityPageTxt').text('很可惜,您没抢到红包');
}else{
$('#endActivityPageTxt').text('成功抢到' + price + '元');
}
$('#activityEnd').show();
}else{
//若有,显示还有下一轮......
$('#redBagInfo').hide();
$("#countdown").hide();
$('#activityEnd').hide();
$("#shake_view").hide();
if( price == 0 ){
$('#promst').text('很可惜,您没抢到红包');
}else{
$('#promst').text('成功抢到' + price + '元');
}
$('#nextRedBagActivity').show();
}
}
}
// 获取当前有效的红包
function getAvailableRedbag(){
var length = redbags.length;
// 没有红包活动返回null
if (length == 0) {
return null;
}
// 遍历红包列表,取到第一个有效的红包,若有则返回当前有效的红包
for(var i = 0; i < length; i++){
var redbag = redbags[i];
var status = redbag.status;
// 主要获取到第一个有效的红包就返回当前有效的红包,并且退出该函数
if (status != '2') {
return redbag;
break;
}
}
// 没有有效的红包,即所有的红包活动都结束了
return null;
}
// 开始摇红包倒计时
function startCount(startTime) {
// var timeContent = $('#timeContent'); //显示倒计时的框
var endTime = new Date(startTime.replace(/-/g,'/')); //红包开始的时间
var countTimer = setInterval(
function() {
var nowTime = new Date();
var time = endTime.getTime() - nowTime.getTime() + time_distance; //截止时间和开始时间相差的毫秒数
if (!isNaN(time) && time >= 0) {
var day = parseInt(time / 1000 / 60 / 60 / 24);
var hour = parseInt(time / 1000 / 60 / 60 % 24);
var minute = parseInt(time / 1000 / 60 % 60);
var second = parseInt(time / 1000 % 60);
if (time == 0) {
current_redbag.status = "1";
refreshView(current_redbag,false);
}else if (time <= 10000) {
// 调用10秒倒计时动画
$('#timeContent').text( second + '秒' );
} else if (time <= 120000) {
// 倒数120秒的时候
var secondLeft = minute * 60 + second;
$('#timeContent').text( secondLeft + '秒');
} else {
$('#timeContent').text( day + '天' + hour + '小时' + minute + '分钟' + second + '秒');
}
} else if (time < 0) {
clearInterval(countTimer);
}
}, 1000
);
}
// 检查红包状态变化的长轮询
function check_redbag_status(redBagId,oldStatus,timeOut,startTime) {
var url = globalConfig.pre_api_url + "/wxwall_api/redbag/check_redbag_status.php"; //检查红包状态的url
var redbag_id = redBagId;
var old_status = oldStatus;
var time_out = timeOut;
var start_time = startTime;
var param = {
"redbag_id": redbag_id,
"old_status": old_status,
"time_out": time_out
};
$.ajax({
// 提交数据的类型
type: "POST",
// 提交的网址
url: url,
// 提交的数据
data: param,
// 返回数据的格式
datatype: "json",
// 在请求之前调用的函数
beforeSend: function() {
},
// 成功返回之后调用的函数
success: function(response) {
response = eval("(" + response + ")");
var status = response.status;
if (status == '2') {
current_redbag.status = response.data.new_status;//很重要
handleRedbag(current_redbag);
if (current_redbag.status == '2') {
return;
}
}
check_redbag_status(redbag_id,current_redbag.status,time_out,start_time);
// console.log(response.msg);
},
// 执行后调用的函数
complete: function(XMLHttpRequest, textStatus) {
// console.log(textStatus);
},
// 调用出错执行的函数
error: function() {
console.log("error");
setTimeout(function(){
check_redbag_status(redbag_id,old_status,time_out,start_time);
}, 500); //这里是500ms吗??失败后果500ms再次请求
},
});
}
// 请求红包列表
function requestRedbags(activity_id){
var get_redbag_list_url = globalConfig.pre_api_url + "/wxwall_api/redbag/get_redbag_list.php"; //获取红包列表的url
data = {
"activity_id": activity_id,
};
// 向后台请求红包列表,并根据每个红包的status进行相应的处理
request(get_redbag_list_url, data, function(response) {
var datas = response.data;
redbags = datas.redbags;
// 当没有红包活动的时候,提示没有红包
if( datas == '' || response.status == '6'){
refreshView(undefined,false);
return;
}
// redbag 存储当前有效的红包或者null
var redbag = getAvailableRedbag();
// 当有红包活动的时候,但是没有有效红包,显示抢到红包的信息
if( redbag === null ){
refreshView(null,false);
return;
}
var servie_time = new Date(datas.current_time.replace(/-/g,'/')); //卸载下面,防止datas=‘’的时候,replace()函数出错
var local_time = new Date();
time_distance = local_time.getTime() - servie_time.getTime(); //服务器和用户的时间相差的毫秒数
// 获取红包列表
var length = redbags.length;
var redbag_id = redbag.id;
var old_status = redbag.status;
var start_time = redbag.start_time;
var time_out = 40;
current_redbag = redbag;
// 处理当前的红包
handleRedbag(redbag);
// 长轮询检测status
check_redbag_status(redbag_id,old_status,time_out,start_time);
});
}
// 处理当前有效的红包
function handleRedbag(redbag){
var status = redbag.status;
var start_time = redbag.start_time;
//
refreshView(redbag,false);
// $("#device_log").append("<li>status:"+status+"<li>");
if (status == '0') {
//显示倒计时
startCount(start_time);
}else if(status == '1'){
//监听摇一摇
if (isTestEnv == true) {
monitor_shake();
}else{
listenPhoneShake();
}
}else if(status == '2'){
// refreshView()函数已经处理了
//结束该轮抢红包,进入了结束界面
//关闭用户可以摇红包的能力
//提示用户是否还有下一轮红包活动,如果有,则引导用户操作;如果没有,提示没有。
}
}
});