node.js chat程序如何实现Ajax long-polling长链接刷新模式_javascript技巧

废话不多说,开始今天的主题。纵观这个程序,感觉它的最可贵之处,在于展示了,如何用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用自身基于事件驱动的语言特点,实现了长链接刷新功能,让我们打开眼界。自我感觉受益匪浅。特此花时间写个教程跟大家分享,同时也加深我自己的理解。

时间: 2024-11-16 09:26:43

node.js chat程序如何实现Ajax long-polling长链接刷新模式_javascript技巧的相关文章

JS this作用域以及GET传输值过长的问题解决方法_javascript技巧

在开发项目的时候,前端遇到两个比较隐蔽的问题. 问题一.专IE7浏览器,IE URL参数过长问题,引发HTTP Status 122报错 原因:在IE6.8下没有什么问题,但在IE7就不兼容get参数过长,google上说"Don't use the GET method in Ajax Apps, if you can void it, because IE7 craps out with more than 2032 characters in a get string" 解决方法

构建一个Node.js应用程序分析公众对Twitter给定主题的反应

作为一位软件应用程序开发人员,我尝试过解决以下问题:如何获得来自用户的直接反馈,尤其是在线用户.举例而言,迅速了解 Twitter 用户对一个应用程序.产品发布.活动或当前事件的反应将会很有帮助.反应是正面.负面还是中立的? 由于我希望应用程序能够快速判定 Twitter 上的公众情绪,所以我希望它能够快速开发,连接一个 Twitter Web 服务,拥有一个简单的移动接口,并快速分析海量数据. 我选择使用 JavaScript 和流行的 Node.js 运行时构建 PaaS 应用程序,将它构建

Windows Azure承载Node.js应用程序进行存储和服务

当我描述如何http://www.aliyun.com/zixun/aggregation/32995.html">在Windows Azure承载Node.js应用程序时,将可能引发一个有关如何使用 Windows Azure 服务,如存储. 服务总线. 访问控制等的问题......在Node.js中与windows azure 服务交互是通过 Windows Azure Node.js SDK,这是一个在NPM中可用的模块. 在这篇文章我想描述了如何使用 Windows Azure 存

不用AJAX和IFRAME,说说真正意义上的ASP+JS无刷新技术_javascript技巧

网上流传的什么<<AJAX vs ASP传统无刷新>>中的ASP无刷新,加个IFRAME,弄个JS根本不能称之为无刷新..... 一下代码未区分大小写,请自行修改! 全静态无刷新思路: <HTML> <SCRIPT SRC=""></SCRIPT>//当前页面全局的 无数新调用 <SCRIPT> //一系列JS调用 FUNCTION XX(FUN_NAME,PARAMETER_NAME,PARAMETER_VALU

JS导出PDF插件的方法(支持中文、图片使用路径)_javascript技巧

在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfmake,很好地解决了此问题.它的效果可以先到http://pdfmake.org/playground.html查看.在使用过程中,还发现图片的插入是相对繁琐的一件事. 针对这些问题,本文的主要内容可分为三部分: •pdfmake的基本使用方法: •如何解决中文问题; •如何通过指定图片地址插入图片. pdfmake的基本使用方法 1.包含以下两个文件 <script src="build/

vue.js通过自定义指令实现数据拉取更新的实现方法_javascript技巧

前言 这篇文章的代码片段位于 vue 的单文件组件中,即以 .vue 结尾的文件中,本文说明的只是一种实现方法,既不是唯一的方法也不是最好的方法,如果大家有更好的方法可以留言,大家进行讨论. 第一步 首先,一定要先定义变量: // app.vue <script> data () { return { // 定义 getData getData:{}, // 定义自定义指令的绑定值 ifUpdate:true } } 第二步 然后要使用 ajax 的话,要在 index.html 里引入 jq

用原生JS对AJAX做简单封装的实例代码_javascript技巧

首先,我们需要xhr对象.这对我们来说不难,封装成一个函数. var createAjax = function() { var xhr = null; try { //IE系列浏览器 xhr = new ActiveXObject("microsoft.xmlhttp"); } catch (e1) { try { //非IE浏览器 xhr = new XMLHttpRequest(); } catch (e2) { window.alert("您的浏览器不支持ajax,请

原生 JS Ajax,GET和POST 请求实例代码_javascript技巧

javascript/js的ajax的GET请求代码如下所示: <script type="text/javascript"> /* 创建 XMLHttpRequest 对象 */ var xmlHttp; function GetXmlHttpObject(){ if (window.XMLHttpRequest){ // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest();

Vue.js Ajax动态参数与列表显示实现方法_javascript技巧

Vue.js简介 vue是法语中视图的意思,Vue.js是一个轻巧.高性能.可组件化的MVVM库,同时拥有非常容易上手的API. 一.动态参数显示 ajax异步请求后,接收到返回的data参数并显示在前端 1.1 引入js,也加入了jQuery <script type="text/javascript" src="/js/vue.min.js"></script> <script type="text/javascript&