node.js chat程式如何?Ajax long-polling長連結重新整理模式

來源:互聯網
上載者:User

廢話不多說,開始今天的主題。縱觀這個程式,感覺它的最可貴之處,在於展示了,如何用nodejs實現長連結模式的重新整理技術。
  (這個程式不詳細介紹,重點講解這個功能)
Client.js  
首先看一段核心代碼: 複製代碼 代碼如下: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中的一段代碼,一看這段代碼,大家應該立馬想到兩個字——“遞迴”。在longPoll方法中,再次調用longPoll方法,典型的遞迴調用。
  根據這段代碼的語義,可以看出,第一次載入時,會調用longPoll方法,非同步向"/resv"擷取值,如果成功了, 執行success的方法,立即再次調用longPoll方法。如果失敗了,執行error函數,隔10秒中再次調用longPoll方法。當然,執行error方法有一定的次數限制,由變數transmission_errorsx控制。
  大家可能會有一個疑問,這樣一直遞迴迴圈擷取資料,伺服器會不會有很大的負擔?在沒有資料可擷取的時候,也會一直這樣迴圈嗎?當然,答案時否定的!並且,nodejs利用自身的特點,很好的處理了這個問題。接著往下看:
Server.js
現看server中如何回應上面client的調用,核心代碼: 複製代碼 代碼如下:fu.get("/recv", function (req, res) {
//對session的驗證和更新......
channel.query(since, function (messages) {
if (session) session.poke();
res.simpleJSON(200, { messages: messages, rss: mem.rss });
});
});

先不要管這個fu.get()是什麼意思,它和本次教程無關。總之知道它能回應client的調用就行了。上面的代碼,除了對session的一些操作之外,只是調用了channel的query方法。注意傳遞的參數:
since,它紀錄了一個時間;
匿名方法,它接受一個messages參數,兩個動作:1 更新session時間,2 返回一個json,即把messages返回給用戶端。
  有人可能會有疑問:在這裡直接返回messages不行嗎,幹嘛還得在一個channel中定義一個方法才操作?答案:如果是那樣,就成了一個死迴圈,server和client每時每刻都進行著資料互動,即使沒有資訊可返回。
  還是接著往下看吧!
  看channel是怎麼定義的: 複製代碼 代碼如下: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() 方法用於把數組的第一個元素從其中刪除,並返回第一個元素的值
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中定義了兩個變數,兩個方法,還有一個每隔3秒執行一次的setInterval函數。
  首先看query方法,
  query方法接收兩個參數:
since:紀錄一個時間
callback:即上面講調用channel.query方法時傳入的那個匿名函數(JS中,函數可以當參數傳遞,接收之後可直接調用。不會趕快補課啊。。。)
  messages裡存的時當前的聊天紀錄隊列,query方法會尋找合格聊天紀錄,把他們放在matching隊列中。如果matching.length>0,則調用callback接收的函數,即把matching以json格式返回client。但是。。。接下來是重點!!! 複製代碼 代碼如下:if (matching.length != 0) {
callback(matching);
} else {
callbacks.push({ timestamp: new Date(), callback: callback });
}

如果matching.length<=0,程式會把callback和目前時間,以json格式,存入一個callbacks隊列中。對!不執行了,因為沒有合格聊天訊息,不需要在client顯示,所以先把這個函數存起來,先不執行。
  那也不能這樣一直存著啊,萬一下一秒有人發聊天訊息怎麼辦?
  接著看appendMessage(添加聊天訊息)方法:
  該方法中,前段部分很好理解,無非是接收傳入的參數,組合成一個m集合,然後用sys.puts在終端顯示一下,再把m插入到messages聊天訊息佇列中。接下來又是重點: 複製代碼 代碼如下:while (callbacks.length > 0) {
//shift() 方法用於把數組的第一個元素從其中刪除,並返回第一個元素的值
callbacks.shift().callback([m]);
}

現在要判斷callbacks有沒有儲存,如果有,就執行一個,刪除一個,知道執行完了為止。因為之前在沒有聊天訊息可返回的時候,有人發出了請求,然後系統沒有執行這些請求,都把他們放在callbacks列表中了。
  現在有人發送了聊天訊息,執行添加方法的時候,要再次把那些沒執行的請求都執行一遍。
  通俗理解可以是:你給我發送請求了,我現在還沒有新訊息可以回覆你,一旦有人發了新訊息,我會立刻回覆你。
  不知道大家理解了沒。。。
  這一步完了,最後一步,是每隔3秒鐘,清空到期的callbacks,是一個setInterval函數,這個不難理解。
總結
  nodejs用自身基於事件驅動的語言特點,實現了長連結重新整理功能,讓我們開啟眼界。自我感覺受益匪淺。特此花時間寫個教程跟大家分享,同時也加深我自己的理解。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.