javascript和jQuery实现网页实时聊天的ajax长轮询


Posted in Javascript onJuly 20, 2016

介绍

大家都知道,HTTP协议是一个属于应用层的面向对象的协议,HTTP 协议一共有五大特点:

1、支持客户/服务器模式;

2、简单快速;

3、灵活;

4、无连接;

5、无状态。

所以一次的请求都是一个单独的事件,和前后都没有联系。所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息。

一直以来的方式无非有这么几种:

1、长连接,即服务器端不断开联系,PHP服务器端用ob系列函数来不停的读取输出,但是相当耗费服务器资源。

2、Flash socket,flash的as3语言,创建一个socket服务器用来处理信息。

3、轮询,顾名思义就是不停地发送查询消息,一有新消息立刻更新,但是会有多次无用请求。

4、长轮询,是轮询的升级版,需要服务器端的配合。

5、websocket,HTML5的通信功能,建立一个与服务器端的专用接口ws协议来进行通讯,兼容可能成为问题。

这篇博文总结一下用JS和JQ两种方式(其实不同就是js和jq的实现),实现AJAX长轮询。

长轮询的思想:

javascript和jQuery实现网页实时聊天的ajax长轮询

如图:用AJAX发送询问信息,服务器在没有信息要返回的时候进入无限等待。由于AJAX异步的特性,PHP在服务器端执行等待不会影响到页面的正常处理。一旦服务器查询到返回信息,服务器返回信息,AJAX用回调函数处理这条信息,同时迅速再次发送一个请求等待服务器处理。

与传统轮询相比,长轮询在服务器没的返回信息的时候进入等待,减少了普通轮询服务器无数次的空回复。可以这样认为,长轮询使服务器每次的返回更有目的性,而不是盲目返回。

长轮询的服务器端实现:

聊天信息存储:

数据库设计为信息ID(msgid),发送人(sender),接收人(receiver),信息内容(content),设置senderRead和receiverRead的目的是标记信息是否已被读取,读取后改变标记,以区别信息是否已经被读取。

create table msg{

msgid int not null primary key auto_increment,


sender char(16) not null,


receiver char(16) not null,


content text, //信息内容用text类型,存储量可达到65535字符


senderRead tinyint enum(0,1) default 0,


receiverRead tinyint enum(0,1) default 0 //设置一个是否已读的flag标记

}

PHP脚本:

 脚本的主要目的是处理来自ajax的每次询问,ajax每次询问就查询一下数据库,看有没有新的信息,如果没有,刚用usleep()函数等待一秒后再次查询,直到有新信息插入数据库并被查到,脚本返回查询到的数据,并退出无限循环,结束脚本。

set_time_limit(0);//设置脚本超时时间为无限,不然在过了超时时间后脚本会自动关闭,轮询失败。
 $link=new mysqli("host","user","password","database");
 $search="select sender,receiver,content from msg where receiverRead=0 limit 1";//限制每次读出一条数据,便于修改其已读flag
 $change="update chat set receiverRead=1 where receiverRead=0 limit 1";
 while (true) { //进入无限循环
 
$res=$link->query($sql); //查询结果
  
 if($res->num_rows!=0){ //当有未读信息时读取信息
  


$link->query($change);//将信息的已读flag设为1
  


$msg=$res->fetch_assoc();
  


$jsonstr=json_encode($msg);//取到信息,将信息用转码为json格式,返回给JS
  


echo $jsonstr;
  


break;//输出信息后退出while循环,结束当前脚本
 

}
 
usleep(1000);//如果没有信息不会进入if块,但会执行一下等待1秒,防止PHP因循环假死。
 }

客户端实现:

客户端的主要任务是设置一个ajax请求函数,每次查询时被调用,当没有信息返回时,服务器端被搁置,当前页面正常执行;当有信息返回时,函数处理返回的数据,并迅速再次调用此函数发送一次请求。

用原生JS:

function link(){
 var xhr=null;//先设置xhr为空,为了轮询时再次调用函数对xhr重用,引发错误
 xhr=new XMLHttpRequest();
 xhr.open('GET','serviceback.php',true);//第三个参数一定要设置为true,异步不阻塞,不会影响到后面JS的执行。
 xhr.send();
 xhr.onreadystatechange=function(){
 
if (xhr.readyState==4) { 严密也可加使用(xhr.readyState==4 && xhr.status ==200)限定服务器响应码为200时才进行处理。
    

if(xhr.responseText!=''){
   



process... //服务器端返回信息,且返回信息不为空,则开始处理返回信息。
  


}
  
setTimeout("link()",300);
//递归再次调用link()函数,用setTimeOut()设置延时是因为服务器端进行sql操作时会耗时,当有新信息时,在服务器将要置已读flag为1还未成功时,AJAX可能已经又发出多条查询信息了,会导致一条信息多次返回。
  
}
 };
}

用jQuery插件实现:

var link={ 



//jQuery的AJAX执行的配置对象
  type:"GET",


//设置请求方式,默认为GET,
  async:true,


//设置是否异步,默认为异步
  url:"customback.php",
  dataType:"json",

//设置期望的返回格式,因服务器返回json格式,这里将数据作为json格式对待
  success:function (msg){
   
 process...
   
setTimeout("link()",300);
  }






//成功时的回调函数,处理返回数据,并且延时建立新的请求连接
}
$.ajax(link);




//执行ajax请求。
]

程序扩充:

添加发送聊天窗口:

新建一个函数用来处理ajax的POST请求,用ajax将发信人,每次发送的信息,收信人发送到服务器端,并设置一个单独的PHP脚本处理信息,将信息插入数据库。

需要注意的是,用JS原生实现POST请求发送信息时,要设置ajax对象的HTTP头,模拟表单提交的操作:

xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");

聊天室消息处理:

为了防止每次都查询到全部信息,我们对数据库的查询操作更改一下,设置idflag=0,每次查询后,设置idflag为查询到的数据的id,查询时我们查询比idflag大的ID,即,新添加进去的信息。

好了,本文到此就结束了,利用本文的示例代码一个简单的聊天室程序就做好了,感兴趣的可以快快实践下了。

Javascript 相关文章推荐
javascript Prototype 对象扩展
May 15 Javascript
基于jquery的当鼠标滚轮到最底端继续加载新数据思路分享(多用于微博、空间、论坛 )
Oct 10 Javascript
详解JavaScript语法对{}处理的坑爹之处
Jun 05 Javascript
jQuery中trigger()方法用法实例
Jan 19 Javascript
浅谈轻量级js模板引擎simplite
Feb 13 Javascript
JS实现左右无缝轮播图代码
May 01 Javascript
AngularJS使用ng-repeat指令实现下拉框
Aug 23 Javascript
手把手教你搭建ES6的开发运行环境
Jul 11 Javascript
Angular4学习教程之HTML属性绑定的方法
Jan 04 Javascript
layui 表格操作列按钮动态显示的实现方法
Sep 06 Javascript
JavaScript canvas绘制圆弧与圆形
Feb 18 Javascript
VUE+elementui组件在table-cell单元格中绘制微型echarts图
Apr 20 Javascript
Node.js如何自动审核团队的代码
Jul 20 #Javascript
js只执行1次的函数示例
Jul 20 #Javascript
JQuery为元素添加样式的实现方法
Jul 20 #Javascript
JCrop+ajaxUpload 图像切割上传的实例代码
Jul 20 #Javascript
javaScript给元素添加多个class的简单实现
Jul 20 #Javascript
JavaScript中数组的22种方法必学(推荐)
Jul 20 #Javascript
JavaScript DOM 对象深入了解
Jul 20 #Javascript
You might like
IIS6.0+PHP5.x+MySQL5.x+Zend3.0x+GD+phpMyAdmin2.8x通用安装实例(已经完成)
2006/12/06 PHP
php下将XML转换为数组
2010/01/01 PHP
php+MySQL判断update语句是否执行成功的方法
2014/08/28 PHP
WampServer下安装多个版本的PHP、mysql、apache图文教程
2015/01/07 PHP
thinkPHP5.0框架事务处理操作简单示例
2018/09/07 PHP
非常不错的一个javascript 类
2006/11/07 Javascript
复制Input内容的js代码_支持所有浏览器,修正了Firefox3.5以上的问题
2010/06/21 Javascript
js原生appendChild的bug解决心得分享
2013/07/01 Javascript
document.execCommand()的用法小结
2014/01/08 Javascript
把字符串按照特定的字母顺序进行排序的js代码
2014/01/28 Javascript
JavaScript中匿名、命名函数的性能测试
2014/09/04 Javascript
JS实现可调整倒计时间代码分享
2015/08/18 Javascript
微信小程序实现自上而下字幕滚动
2018/07/14 Javascript
Vue Extends 扩展选项用法完整实例
2019/09/17 Javascript
js实现上传图片并显示图片名称
2019/12/18 Javascript
Javascript如何实现扩充基本类型
2020/08/26 Javascript
Antd表格滚动 宽度自适应 不换行的实例
2020/10/27 Javascript
element 动态合并表格的步骤
2020/12/31 Javascript
[02:02]2018DOTA2亚洲邀请赛Mineski赛前采访
2018/04/04 DOTA
Python批量按比例缩小图片脚本分享
2015/05/21 Python
Python基于列表list实现的CRUD操作功能示例
2018/01/05 Python
Python进阶之尾递归的用法实例
2018/01/31 Python
python内存动态分配过程详解
2019/07/15 Python
xadmin使用formfield_for_dbfield函数过滤下拉表单实例
2020/04/07 Python
加拿大城市本地限时优惠:Buytopia.ca
2018/09/19 全球购物
空字符串(“”)和null的区别
2012/11/13 面试题
演讲稿开场白
2014/01/13 职场文书
大龄毕业生求职别忘职业规划
2014/03/11 职场文书
《分一分》教学反思
2014/04/13 职场文书
小学生环保演讲稿
2014/04/25 职场文书
2014年评职称工作总结
2014/11/20 职场文书
工程技术负责人岗位职责
2015/04/13 职场文书
2016年五一促销广告语
2016/01/28 职场文书
2016年学生会感恩节活动总结
2016/04/01 职场文书
tensorflow中的数据类型dtype用法说明
2021/05/26 Python
Python os和os.path模块详情
2022/04/02 Python