javascript和jQuery實(shí)現(xiàn)網(wǎng)頁(yè)實(shí)時(shí)聊天的ajax長(zhǎng)輪詢
介紹
大家都知道,HTTP協(xié)議是一個(gè)屬于應(yīng)用層的面向?qū)ο蟮膮f(xié)議,HTTP 協(xié)議一共有五大特點(diǎn):
1、支持客戶/服務(wù)器模式;
2、簡(jiǎn)單快速;
3、靈活;
4、無(wú)連接;
5、無(wú)狀態(tài)。
所以一次的請(qǐng)求都是一個(gè)單獨(dú)的事件,和前后都沒(méi)有聯(lián)系。所以我們?cè)诮鉀Q網(wǎng)頁(yè)實(shí)時(shí)聊天時(shí)就遇到一個(gè)問(wèn)題,如何保證與服務(wù)器的長(zhǎng)時(shí)間聯(lián)系,從而源源不段地獲取信息。
一直以來(lái)的方式無(wú)非有這么幾種:
1、長(zhǎng)連接,即服務(wù)器端不斷開(kāi)聯(lián)系,PHP服務(wù)器端用ob系列函數(shù)來(lái)不停的讀取輸出,但是相當(dāng)耗費(fèi)服務(wù)器資源。
2、Flash socket,flash的as3語(yǔ)言,創(chuàng)建一個(gè)socket服務(wù)器用來(lái)處理信息。
3、輪詢,顧名思義就是不停地發(fā)送查詢消息,一有新消息立刻更新,但是會(huì)有多次無(wú)用請(qǐng)求。
4、長(zhǎng)輪詢,是輪詢的升級(jí)版,需要服務(wù)器端的配合。
5、websocket,HTML5的通信功能,建立一個(gè)與服務(wù)器端的專用接口ws協(xié)議來(lái)進(jìn)行通訊,兼容可能成為問(wèn)題。
這篇博文總結(jié)一下用JS和JQ兩種方式(其實(shí)不同就是js和jq的實(shí)現(xiàn)),實(shí)現(xiàn)AJAX長(zhǎng)輪詢。
長(zhǎng)輪詢的思想:
如圖:用AJAX發(fā)送詢問(wèn)信息,服務(wù)器在沒(méi)有信息要返回的時(shí)候進(jìn)入無(wú)限等待。由于AJAX異步的特性,PHP在服務(wù)器端執(zhí)行等待不會(huì)影響到頁(yè)面的正常處理。一旦服務(wù)器查詢到返回信息,服務(wù)器返回信息,AJAX用回調(diào)函數(shù)處理這條信息,同時(shí)迅速再次發(fā)送一個(gè)請(qǐng)求等待服務(wù)器處理。
與傳統(tǒng)輪詢相比,長(zhǎng)輪詢?cè)诜?wù)器沒(méi)的返回信息的時(shí)候進(jìn)入等待,減少了普通輪詢服務(wù)器無(wú)數(shù)次的空回復(fù)??梢赃@樣認(rèn)為,長(zhǎng)輪詢使服務(wù)器每次的返回更有目的性,而不是盲目返回。
長(zhǎng)輪詢的服務(wù)器端實(shí)現(xiàn):
聊天信息存儲(chǔ):
數(shù)據(jù)庫(kù)設(shè)計(jì)為信息ID(msgid),發(fā)送人(sender),接收人(receiver),信息內(nèi)容(content),設(shè)置senderRead和receiverRead的目的是標(biāo)記信息是否已被讀取,讀取后改變標(biāo)記,以區(qū)別信息是否已經(jīng)被讀取。
create table msg{ msgid int not null primary key auto_increment, sender char(16) not null, receiver char(16) not null, content text, //信息內(nèi)容用text類型,存儲(chǔ)量可達(dá)到65535字符 senderRead tinyint enum(0,1) default 0, receiverRead tinyint enum(0,1) default 0 //設(shè)置一個(gè)是否已讀的flag標(biāo)記 }
PHP腳本:
腳本的主要目的是處理來(lái)自ajax的每次詢問(wèn),ajax每次詢問(wèn)就查詢一下數(shù)據(jù)庫(kù),看有沒(méi)有新的信息,如果沒(méi)有,剛用usleep()函數(shù)等待一秒后再次查詢,直到有新信息插入數(shù)據(jù)庫(kù)并被查到,腳本返回查詢到的數(shù)據(jù),并退出無(wú)限循環(huán),結(jié)束腳本。
set_time_limit(0);//設(shè)置腳本超時(shí)時(shí)間為無(wú)限,不然在過(guò)了超時(shí)時(shí)間后腳本會(huì)自動(dòng)關(guān)閉,輪詢失敗。 $link=new mysqli("host","user","password","database"); $search="select sender,receiver,content from msg where receiverRead=0 limit 1";//限制每次讀出一條數(shù)據(jù),便于修改其已讀flag $change="update chat set receiverRead=1 where receiverRead=0 limit 1"; while (true) { //進(jìn)入無(wú)限循環(huán) $res=$link->query($sql); //查詢結(jié)果 if($res->num_rows!=0){ //當(dāng)有未讀信息時(shí)讀取信息 $link->query($change);//將信息的已讀flag設(shè)為1 $msg=$res->fetch_assoc(); $jsonstr=json_encode($msg);//取到信息,將信息用轉(zhuǎn)碼為json格式,返回給JS echo $jsonstr; break;//輸出信息后退出while循環(huán),結(jié)束當(dāng)前腳本 } usleep(1000);//如果沒(méi)有信息不會(huì)進(jìn)入if塊,但會(huì)執(zhí)行一下等待1秒,防止PHP因循環(huán)假死。 }
客戶端實(shí)現(xiàn):
客戶端的主要任務(wù)是設(shè)置一個(gè)ajax請(qǐng)求函數(shù),每次查詢時(shí)被調(diào)用,當(dāng)沒(méi)有信息返回時(shí),服務(wù)器端被擱置,當(dāng)前頁(yè)面正常執(zhí)行;當(dāng)有信息返回時(shí),函數(shù)處理返回的數(shù)據(jù),并迅速再次調(diào)用此函數(shù)發(fā)送一次請(qǐng)求。
用原生JS:
function link(){ var xhr=null;//先設(shè)置xhr為空,為了輪詢時(shí)再次調(diào)用函數(shù)對(duì)xhr重用,引發(fā)錯(cuò)誤 xhr=new XMLHttpRequest(); xhr.open('GET','serviceback.php',true);//第三個(gè)參數(shù)一定要設(shè)置為true,異步不阻塞,不會(huì)影響到后面JS的執(zhí)行。 xhr.send(); xhr.onreadystatechange=function(){ if (xhr.readyState==4) { 嚴(yán)密也可加使用(xhr.readyState==4 && xhr.status ==200)限定服務(wù)器響應(yīng)碼為200時(shí)才進(jìn)行處理。 if(xhr.responseText!=''){ process... //服務(wù)器端返回信息,且返回信息不為空,則開(kāi)始處理返回信息。 } setTimeout("link()",300); //遞歸再次調(diào)用link()函數(shù),用setTimeOut()設(shè)置延時(shí)是因?yàn)榉?wù)器端進(jìn)行sql操作時(shí)會(huì)耗時(shí),當(dāng)有新信息時(shí),在服務(wù)器將要置已讀flag為1還未成功時(shí),AJAX可能已經(jīng)又發(fā)出多條查詢信息了,會(huì)導(dǎo)致一條信息多次返回。 } }; }
用jQuery插件實(shí)現(xiàn):
var link={ //jQuery的AJAX執(zhí)行的配置對(duì)象 type:"GET", //設(shè)置請(qǐng)求方式,默認(rèn)為GET, async:true, //設(shè)置是否異步,默認(rèn)為異步 url:"customback.php", dataType:"json", //設(shè)置期望的返回格式,因服務(wù)器返回json格式,這里將數(shù)據(jù)作為json格式對(duì)待 success:function (msg){ process... setTimeout("link()",300); } //成功時(shí)的回調(diào)函數(shù),處理返回?cái)?shù)據(jù),并且延時(shí)建立新的請(qǐng)求連接 } $.ajax(link); //執(zhí)行ajax請(qǐng)求。]
程序擴(kuò)充:
添加發(fā)送聊天窗口:
新建一個(gè)函數(shù)用來(lái)處理ajax的POST請(qǐng)求,用ajax將發(fā)信人,每次發(fā)送的信息,收信人發(fā)送到服務(wù)器端,并設(shè)置一個(gè)單獨(dú)的PHP腳本處理信息,將信息插入數(shù)據(jù)庫(kù)。
需要注意的是,用JS原生實(shí)現(xiàn)POST請(qǐng)求發(fā)送信息時(shí),要設(shè)置ajax對(duì)象的HTTP頭,模擬表單提交的操作:
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
聊天室消息處理:
為了防止每次都查詢到全部信息,我們對(duì)數(shù)據(jù)庫(kù)的查詢操作更改一下,設(shè)置idflag=0,每次查詢后,設(shè)置idflag為查詢到的數(shù)據(jù)的id,查詢時(shí)我們查詢比idflag大的ID,即,新添加進(jìn)去的信息。
好了,本文到此就結(jié)束了,利用本文的示例代碼一個(gè)簡(jiǎn)單的聊天室程序就做好了,感興趣的可以快快實(shí)踐下了。
- js實(shí)現(xiàn)簡(jiǎn)易聊天對(duì)話框
- nodejs實(shí)現(xiàn)的一個(gè)簡(jiǎn)單聊天室功能分享
- 使用Angular和Nodejs、socket.io搭建聊天室及多人聊天室
- nw.js實(shí)現(xiàn)類似微信的聊天軟件
- Vue.js仿微信聊天窗口展示組件功能
- JavaScript/jQuery、HTML、CSS 構(gòu)建 Web IM 遠(yuǎn)程及時(shí)聊天通信程序
- js編寫(xiě)簡(jiǎn)單的聊天室功能
- nodejs基于WS模塊實(shí)現(xiàn)WebSocket聊天功能的方法
- AngularJS+Node.js實(shí)現(xiàn)在線聊天室
- JavaScript實(shí)現(xiàn)簡(jiǎn)易QQ聊天界面
相關(guān)文章
淺析JavaScript中的變量復(fù)制、參數(shù)傳遞和作用域鏈
這篇文章主要介紹了淺析JavaScript中的變量復(fù)制、參數(shù)傳遞和作用域鏈 的相關(guān)資料,需要的朋友可以參考下2016-01-01動(dòng)態(tài)生成的IFRAME,設(shè)置SRC時(shí)的,不同位置帶來(lái)的影響
動(dòng)態(tài)生成的IFRAME,設(shè)置SRC時(shí)的,不同位置帶來(lái)的影響。 以下所說(shuō)的是在IE7下運(yùn)行的。IE6下也是同樣。 在這個(gè)blog中,直接點(diǎn)擊運(yùn)行代碼,和把下面代碼保存到為網(wǎng)頁(yè)在運(yùn)行(以本地文件或域名訪問(wèn)),效果不一樣。2008-03-03JavaScript中數(shù)組的排序、亂序和搜索實(shí)現(xiàn)代碼
JavaScript中實(shí)現(xiàn)數(shù)組的排序、亂序和搜索,其實(shí)所有這些功能,用一個(gè)sort()就可以完成了2011-11-11開(kāi)源免費(fèi)天氣預(yù)報(bào)接口API及全國(guó)所有地區(qū)代碼(國(guó)家氣象局提供)
這篇文章主要介紹了開(kāi)源免費(fèi)天氣預(yù)報(bào)接口API及全國(guó)所有地區(qū)代碼(國(guó)家氣象局提供)的相關(guān)資料,需要的朋友可以參考下2016-12-12利用JavaScript腳本實(shí)現(xiàn)滾屏效果的方法
這篇文章主要介紹了利用JavaScript腳本實(shí)現(xiàn)滾屏效果的方法,即一個(gè)公告欄顯示般的效果,需要的朋友可以參考下2015-07-07用javascript對(duì)一個(gè)json數(shù)組深度賦值示例
本節(jié)主要介紹了用javascript對(duì)一個(gè)json數(shù)組深度賦值的具體實(shí)現(xiàn),需要的朋友可以參考下2014-07-07如何通過(guò)vscode運(yùn)行調(diào)試javascript代碼
這篇文章主要介紹了如何通過(guò)vscode運(yùn)行調(diào)試javascript代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07神奇的代碼 通殺各種網(wǎng)站-可隨意修改復(fù)制頁(yè)面內(nèi)容
在瀏覽器地址欄輸入這一行代碼,然后回車,就發(fā)現(xiàn)整個(gè)頁(yè)面都可以隨意編輯了。僅僅是一行很短的代碼。2008-07-07javascript 支持ie和firefox杰奇翻頁(yè)函數(shù)
杰奇小說(shuō)系統(tǒng)用到的翻頁(yè)函數(shù),支持firefox,官方自帶的模板不支持,這樣大家就可以用firefox瀏覽網(wǎng)頁(yè)了,在網(wǎng)頁(yè)木馬橫行的今天,firefox比ie要安全不少2008-07-07