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 相关文章推荐
jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍
Apr 07 Javascript
用原生JavaScript实现jQuery的$.getJSON的解决方法
May 03 Javascript
Javascript中的for in循环和hasOwnProperty结合使用
Jun 05 Javascript
javascript获取浏览器类型和版本的方法(js获取浏览器版本)
Mar 13 Javascript
当滚动条滚动到页面底部自动加载增加内容的js代码
May 13 Javascript
JS实现的用来对比两个用指定分隔符分割的字符串是否相同
Sep 19 Javascript
JavaScript中的slice()方法使用详解
Jun 06 Javascript
判断JS对象是否拥有某属性的方法推荐
May 12 Javascript
jquery mobile 实现自定义confirm确认框效果的简单实例
Jun 17 Javascript
AngularJS控制器之间的通信方式详解
Nov 03 Javascript
Bootstrap Search Suggest使用例子
Dec 21 Javascript
react使用CSS实现react动画功能示例
May 18 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
ioncube_loader_win_5.2.dll的错误解决方法
2015/01/04 PHP
PHP合并discuz用户脚本的方法
2015/08/04 PHP
JavaScript this调用规则说明
2010/03/08 Javascript
Javascript 通过json自动生成Dom的代码
2010/04/01 Javascript
可以用来调试JavaScript错误的解决方案
2010/08/07 Javascript
『jQuery』名称冲突使用noConflict方法解决
2013/04/22 Javascript
js中数组Array的一些常用方法总结
2013/08/12 Javascript
js实现无需数据库的县级以上联动行政区域下拉控件
2013/08/14 Javascript
浅谈javascript中字符串String与数组Array
2014/12/31 Javascript
js实现具有高亮显示效果的多级菜单代码
2015/09/01 Javascript
Bootstrap布局之栅格系统详解
2016/06/13 Javascript
使用vue.js制作分页组件
2016/06/27 Javascript
Node.js实现文件上传
2016/07/05 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
2016/08/13 Javascript
BooStrap对导航条的改造实践小结
2016/09/21 Javascript
JavaScript获取键盘按键的键码(参照表)
2017/01/10 Javascript
JS+canvas实现的五子棋游戏【人机大战版】
2017/07/19 Javascript
node+vue实现用户注册和头像上传的实例代码
2017/07/20 Javascript
JavaScript面向对象精要(下部)
2017/09/12 Javascript
原生JS获取元素的位置与尺寸实现方法
2017/10/18 Javascript
浅谈Vue数据响应思路之数组
2018/11/06 Javascript
vue-router的使用方法及含参数的配置方法
2018/11/13 Javascript
用WebStorm进行Angularjs 2开发(环境篇:Windows 10,Angular-cli方式)
2018/12/05 Javascript
详解vue中v-model和v-bind绑定数据的异同
2020/08/10 Javascript
[41:41]TFT vs Secret Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
python统计cpu利用率的方法
2015/06/02 Python
将Pytorch模型从CPU转换成GPU的实现方法
2019/08/19 Python
Python中内建模块collections如何使用
2020/05/27 Python
UNIONBAY官网:美国青少年服装品牌
2019/03/26 全球购物
最畅销的视频游戏享受高达90%的折扣:CDKeys
2020/02/10 全球购物
贷款担保书范文
2014/05/13 职场文书
2014年行政助理工作总结
2014/11/19 职场文书
慰问信的写作格式及范文!
2019/06/24 职场文书
2019年消防宣传标语集锦
2019/11/21 职场文书
JS一分钟在github+Jekyll的博客中添加访问量功能的实现
2021/04/03 Javascript
使用CSS实现百叶窗效果示例代码
2023/05/07 HTML / CSS