最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

node.js chat程序如何實(shí)現(xiàn)Ajax long-polling長(zhǎng)鏈接刷新模式

 更新時(shí)間:2012年03月13日 22:59:48   作者:  
node.js chat是node.js作者用JS寫(xiě)的一個(gè)多人聊天工具, 源代碼公開(kāi)下載,網(wǎng)址是chat.nodejs.org。作者用這個(gè)小例子,來(lái)展示如何用nodejs開(kāi)發(fā)高效率的應(yīng)用程序。對(duì)于nodejs的學(xué)習(xí)者來(lái)說(shuō),是一個(gè)很好的例子
廢話不多說(shuō),開(kāi)始今天的主題??v觀這個(gè)程序,感覺(jué)它的最可貴之處,在于展示了,如何用nodejs實(shí)現(xiàn)長(zhǎng)鏈接模式的刷新技術(shù)。
 ?。ㄟ@個(gè)程序不詳細(xì)介紹,重點(diǎn)講解這個(gè)功能)
Client.js  
首先看一段核心代碼:
復(fù)制代碼 代碼如下:

function longPoll (data) {
//....此處省略**行
$.ajax({ cache: false
, type: "GET"
, url: "/recv"
, dataType: "json"
, data: { since: CONFIG.last_message_time, id: CONFIG.id }
, error: function () {
addMessage("", "long poll error. trying again...", new Date(), "error");
transmission_errors += 1;
//don't flood the servers on error, wait 10 seconds before retrying
setTimeout(longPoll, 10*1000);
}
, success: function (data) {
transmission_errors = 0;
//if everything went well, begin another request immediately
//the server will take a long time to respond
//how long? well, it will wait until there is another message
//and then it will return it to us and close the connection.
//since the connection is closed when we get data, we longPoll again
longPoll(data);
}
});
}

這是client.js中的一段代碼,一看這段代碼,大家應(yīng)該立馬想到兩個(gè)字——“遞歸”。在longPoll方法中,再次調(diào)用longPoll方法,典型的遞歸調(diào)用。
  根據(jù)這段代碼的語(yǔ)義,可以看出,第一次加載時(shí),會(huì)調(diào)用longPoll方法,異步向"/resv"獲取值,如果成功了, 執(zhí)行success的方法,立即再次調(diào)用longPoll方法。如果失敗了,執(zhí)行error函數(shù),隔10秒中再次調(diào)用longPoll方法。當(dāng)然,執(zhí)行error方法有一定的次數(shù)限制,由變量transmission_errorsx控制。
  大家可能會(huì)有一個(gè)疑問(wèn),這樣一直遞歸循環(huán)獲取數(shù)據(jù),服務(wù)器會(huì)不會(huì)有很大的負(fù)擔(dān)?在沒(méi)有數(shù)據(jù)可獲取的時(shí)候,也會(huì)一直這樣循環(huán)嗎?當(dāng)然,答案時(shí)否定的!并且,nodejs利用自身的特點(diǎn),很好的處理了這個(gè)問(wèn)題。接著往下看:
Server.js
現(xiàn)看server中如何回應(yīng)上面client的調(diào)用,核心代碼:
復(fù)制代碼 代碼如下:

fu.get("/recv", function (req, res) {
//對(duì)session的驗(yàn)證和更新......
channel.query(since, function (messages) {
if (session) session.poke();
res.simpleJSON(200, { messages: messages, rss: mem.rss });
});
});

先不要管這個(gè)fu.get()是什么意思,它和本次教程無(wú)關(guān)。總之知道它能回應(yīng)client的調(diào)用就行了。上面的代碼,除了對(duì)session的一些操作之外,只是調(diào)用了channel的query方法。注意傳遞的參數(shù):
since,它紀(jì)錄了一個(gè)時(shí)間;
匿名方法,它接受一個(gè)messages參數(shù),兩個(gè)動(dòng)作:1 更新session時(shí)間,2 返回一個(gè)json,即把messages返回給客戶(hù)端。
  有人可能會(huì)有疑問(wèn):在這里直接返回messages不行嗎,干嘛還得在一個(gè)channel中定義一個(gè)方法才操作?答案:如果是那樣,就成了一個(gè)死循環(huán),server和client每時(shí)每刻都進(jìn)行著數(shù)據(jù)交互,即使沒(méi)有信息可返回。
  還是接著往下看吧!
  看channel是怎么定義的:
復(fù)制代碼 代碼如下:

var MESSAGE_BACKLOG = 200,
SESSION_TIMEOUT = 60 * 1000;
var channel = new function () {
var messages = [],
callbacks = [];
this.appendMessage = function (nick, type, text) {
var m = { nick: nick
, type: type // "msg", "join", "part"
, text: text
, timestamp: (new Date()).getTime()
};
switch (type) {
case "msg":
sys.puts("<" + nick + "> " + text);
break;
case "join":
sys.puts(nick + " join");
break;
case "part":
sys.puts(nick + " part");
break;
}
messages.push( m );
while (callbacks.length > 0) {
//shift() 方法用于把數(shù)組的第一個(gè)元素從其中刪除,并返回第一個(gè)元素的值
callbacks.shift().callback([m]);
}
while (messages.length > MESSAGE_BACKLOG)
messages.shift();
};
this.query = function (since, callback) {
var matching = [];
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
if (message.timestamp > since)
matching.push(message)
}
if (matching.length != 0) {
callback(matching);
} else {
callbacks.push({ timestamp: new Date(), callback: callback });
}
};
// clear old callbacks
// they can hang around for at most 30 seconds.
setInterval(function () {
var now = new Date();
while (callbacks.length > 0 && now - callbacks[0].timestamp > 30*1000) {
callbacks.shift().callback([]);
}
}, 3000);
};

channel中定義了兩個(gè)變量,兩個(gè)方法,還有一個(gè)每隔3秒執(zhí)行一次的setInterval函數(shù)。
  首先看query方法,
  query方法接收兩個(gè)參數(shù):
since:紀(jì)錄一個(gè)時(shí)間
callback:即上面講調(diào)用channel.query方法時(shí)傳入的那個(gè)匿名函數(shù)(JS中,函數(shù)可以當(dāng)參數(shù)傳遞,接收之后可直接調(diào)用。不會(huì)趕快補(bǔ)課啊。。。)
  messages里存的時(shí)當(dāng)前的聊天紀(jì)錄隊(duì)列,query方法會(huì)查找符合條件的聊天紀(jì)錄,把他們放在matching隊(duì)列中。如果matching.length>0,則調(diào)用callback接收的函數(shù),即把matching以json格式返回client。但是。。。接下來(lái)是重點(diǎn)?。。?
復(fù)制代碼 代碼如下:

if (matching.length != 0) {
callback(matching);
} else {
callbacks.push({ timestamp: new Date(), callback: callback });
}

如果matching.length<=0,程序會(huì)把callback和當(dāng)前時(shí)間,以json格式,存入一個(gè)callbacks隊(duì)列中。對(duì)!不執(zhí)行了,因?yàn)闆](méi)有符合條件的聊天消息,不需要在client顯示,所以先把這個(gè)函數(shù)存起來(lái),先不執(zhí)行。
  那也不能這樣一直存著啊,萬(wàn)一下一秒有人發(fā)聊天消息怎么辦?
  接著看appendMessage(添加聊天消息)方法:
  該方法中,前段部分很好理解,無(wú)非是接收傳入的參數(shù),組合成一個(gè)m集合,然后用sys.puts在終端顯示一下,再把m插入到messages聊天消息隊(duì)列中。接下來(lái)又是重點(diǎn):
復(fù)制代碼 代碼如下:

while (callbacks.length > 0) {
//shift() 方法用于把數(shù)組的第一個(gè)元素從其中刪除,并返回第一個(gè)元素的值
callbacks.shift().callback([m]);
}

現(xiàn)在要判斷callbacks有沒(méi)有儲(chǔ)存,如果有,就執(zhí)行一個(gè),刪除一個(gè),知道執(zhí)行完了為止。因?yàn)橹霸跊](méi)有聊天消息可返回的時(shí)候,有人發(fā)出了請(qǐng)求,然后系統(tǒng)沒(méi)有執(zhí)行這些請(qǐng)求,都把他們放在callbacks列表中了。
  現(xiàn)在有人發(fā)送了聊天消息,執(zhí)行添加方法的時(shí)候,要再次把那些沒(méi)執(zhí)行的請(qǐng)求都執(zhí)行一遍。
  通俗理解可以是:你給我發(fā)送請(qǐng)求了,我現(xiàn)在還沒(méi)有新消息可以答復(fù)你,一旦有人發(fā)了新消息,我會(huì)立刻答復(fù)你。
  不知道大家理解了沒(méi)。。。
  這一步完了,最后一步,是每隔3秒鐘,清空過(guò)期的callbacks,是一個(gè)setInterval函數(shù),這個(gè)不難理解。
總結(jié)
  nodejs用自身基于事件驅(qū)動(dòng)的語(yǔ)言特點(diǎn),實(shí)現(xiàn)了長(zhǎng)鏈接刷新功能,讓我們打開(kāi)眼界。自我感覺(jué)受益匪淺。特此花時(shí)間寫(xiě)個(gè)教程跟大家分享,同時(shí)也加深我自己的理解。

相關(guān)文章

  • 使用JavaScript italics方法實(shí)現(xiàn)文本變斜體教程示例

    使用JavaScript italics方法實(shí)現(xiàn)文本變斜體教程示例

    這篇文章主要為大家介紹了JavaScript italics實(shí)現(xiàn)文本變斜體教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • javascript先序遍歷DOM樹(shù)的方法

    javascript先序遍歷DOM樹(shù)的方法

    這篇文章主要介紹了5種javascript先序遍歷DOM樹(shù)的方法,感興趣的小伙伴們可以參考一下
    2016-02-02
  • JS+HTML5 FileReader實(shí)現(xiàn)文件上傳前本地預(yù)覽功能

    JS+HTML5 FileReader實(shí)現(xiàn)文件上傳前本地預(yù)覽功能

    這篇文章主要為大家詳細(xì)介紹了JS+HTML5 FileReader實(shí)現(xiàn)文件上傳前本地預(yù)覽功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 微信小程序中遇到的iOS兼容性問(wèn)題小結(jié)

    微信小程序中遇到的iOS兼容性問(wèn)題小結(jié)

    這篇文章主要給大家介紹了關(guān)于微信小程序中遇到的一些iOS兼容性問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • 20個(gè)非常有用的PHP類(lèi)庫(kù) 加速php開(kāi)發(fā)

    20個(gè)非常有用的PHP類(lèi)庫(kù) 加速php開(kāi)發(fā)

    下面是一些非常有用的PHP類(lèi)庫(kù),相信一定可以為你的WEB開(kāi)發(fā)提供更好和更為快速的方法。
    2010-01-01
  • 微信小程序?qū)崿F(xiàn)抖音播放效果的實(shí)例代碼

    微信小程序?qū)崿F(xiàn)抖音播放效果的實(shí)例代碼

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)抖音播放效果的實(shí)例代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • JavaScript簡(jiǎn)寫(xiě)技巧總結(jié)

    JavaScript簡(jiǎn)寫(xiě)技巧總結(jié)

    這篇文章總結(jié)了JavaScript的一些簡(jiǎn)寫(xiě)技巧,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • angular-tree-component的使用詳解

    angular-tree-component的使用詳解

    這篇文章主要介紹了angular-tree-component的使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • webgl實(shí)現(xiàn)物體描邊效果的方法介紹

    webgl實(shí)現(xiàn)物體描邊效果的方法介紹

    這篇文章主要給大家介紹了關(guān)于webgl實(shí)現(xiàn)物體描邊效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用webgl具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • VS2008中使用JavaScript調(diào)用WebServices

    VS2008中使用JavaScript調(diào)用WebServices

    這篇文章主要介紹了VS2008中使用JavaScript調(diào)用WebServices,需要的朋友可以參考下
    2014-12-12

最新評(píng)論

建始县| 右玉县| 新和县| 营山县| 东明县| 桂东县| 当阳市| 祥云县| 毕节市| 杂多县| 和田市| 都江堰市| 都兰县| 林芝县| 彩票| 太保市| 乌拉特前旗| 湖北省| 宁城县| 岐山县| 深泽县| 怀仁县| 亚东县| 前郭尔| 津市市| 文水县| 呈贡县| 屏山县| 和林格尔县| 竹北市| 德安县| 镇坪县| 永康市| 绵阳市| 武邑县| 治县。| 杭锦后旗| 洱源县| 鄂温| 桐城市| 蒙山县|