请注意这个实时打上了双引号,没有绝对的实时,只是时间的颗粒不同罢了(1ms,1s,1m)。html
服务器数据有更新能够快速通知客户端。Web 基于取得模式,而服务器创建大量的和客户端链接来提供数据实时更新反而拉低服务器的使用效能。ajax
IE ActiveX(flash)控件,还有其余浏览器好比Firefox插件。这种基于浏览器外部插件的,因为移植性差。主要要在一些浏览器安全上获得应用。好比在线支付(支付宝),自动登录(QQ)。和一些内网控制(电网内部控制管理)。 Flash 其实也是浏览器的一种插件后台经过创建Socket 来与客户端实时数据更新。这点比较有优点的是Flash 插件几乎每台机器上都有安装,移植性没有问题。但一样对防火墙穿透能力差,并且须要消耗服务器大量的。数据库
Ajax 经过定时去询问服务器是否有数据更新,彷佛是一个通用的解决方案,如:1元xx 类的网站,由于抢购模式须要实现更新商品的剩余份数。好比要获取服务器当前参与人数,获取最新购买人数,发送的私信,好友消息,每一种类型数据都设定一个时间如:1秒到数据库取一次数据。而大多数请求的连接是无效的,并且过多的请求会致使浏览器无响应。 api
客户端脚本须要一个能够告知的程序,告诉咱们服务器中有数据更新了,而后执行本身注册好的程序到服务器取对应的数据。浏览器
咱们只须要服务器通知提供这样的数据结构:缓存
{ //用户消息更新时间 msg: '20141192003261234', //网站购买记录更新时间 buy: '20141192003534567' }
获取客户端获取当前的数据后 和本身当前浏览器中存储的用户消息更新时间进行对比。若是msg更新时间与服务器给的时间彻底一致,咱们就没有必要到服务器中去用户我的消息了,反之服务器中消息更新,开始执行咱们预约的程序来获取服务器,用户收到的消息。显示给用户,而且设置一下当前消息的更新时间。安全
咱们的须要的就这么简单——须要一个通知程序通知咱们服务器
让服务器通知客户端程序数据更新显然不是很划算的事情咱们上面讨论过了,因此咱们须要在客户端设置一个循环往复的定时程序到服务器里面去取注册好的类型(用户消息,网站成交数量,购买人次,商品剩余数量)的更新的时间,经过对于注册对于数据类型的时间来判断要不要执行咱们注册好的方法。数据结构
Ajax异步递归。app
不一样的页面注册不一样的监听信息。
设置互斥量.
须要一个存储介质,存储对应类型信息的更新时间
Try ... Catch... $.ajax error.
客户端定时程序:
//客户端监听对象 var listener = { tid: 0, keys: "", //任务存储对象 taskType: {}, //注册一个任务 appendTaskType: function (key, type) { if (typeof (type) == "function" && typeof (key) == "string" && /^[a-z0-9]+$/.test(key)) { //添加一个任务 this.taskType[key] = { //任务执行函数 fun: type, //变化量 ts: '' }; var a = []; for (var k in this.taskType) { a.push(k); } this.keys = a.join('.'); } }, //开始运行监听 start: function () { //若是定时器正在运行则返回 if (this.tid != 0) return; fn(); //私有定时执行方法 function fn() { $.getJSON("/api/listener", { keys: listener.keys }, function (d) { //获取定时器全部的注册类型 for (var key in listener.taskType) { //获取注册类型对象 var O = listener.taskType[key]; //判断当前对象是否存在和当前的值是否和以前的变化值同样,是否真正执行 if (d[key] && d[key] != O.ts) { //更改现有状态 O.ts = d[key]; //执行注册函数 O.fun(O); } } //设置ID listener.tid = setTimeout(fn, 1000); }) } }, //关闭监听 stop: function () { //清除定时器 clearTimeout(this.tid); //归零 this.tid = 0; } } //注册对页面的监听 listener.appendTaskType("msg", function () { $.getJSON("/api/getlist", { key: 'msg' }, function (data) { var b = $("#msgList"); b.hide(); b.empty(); var html = ''; for (var i = 0; i < data.length; i++) { html += "<li>【" + data[i].user + "】说:" + data[i].msg + "</li>" } b.html(html); b.slideDown(300); }) }); //注册对购买记录的监听 listener.appendTaskType("buy", function () { $.getJSON("/api/getlist", { key: 'buy' }, function (data) { var b = $("#buyList"); b.hide(); b.empty(); var html = ''; for (var i = 0; i < data.length; i++) { html += "<li>【" + data[i].user + "】购买了:" + data[i].msg + "</li>" } b.html(html); b.slideDown(300); }) }) //开始执行监放任务 listener.start();
服务器代码:
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class ApiController : Controller { // // GET: /Api/ /// <summary> /// 根据缓存Key获取当前缓存最后更新的标示 /// </summary> /// <param name="cacheKey">缓存Key</param> /// <returns>最后更新的时间</returns> public string getlast(string cacheKey) { List<data> ls = HttpRuntime.Cache.Get(cacheKey) as List<data>; if (ls != null) return ls.First().time; return "0"; } /// <summary> /// 服务器定时方法,这个方法是检测,数据有没有进行更新 /// </summary> /// <returns></returns> public ContentResult Listener(string keys) { if (string.IsNullOrWhiteSpace(keys)) return Content("{}"); System.Text.StringBuilder builder = new System.Text.StringBuilder("{"); //客户端须要知道用户信息是否变更 if (keys.Contains("msg")) { builder.AppendFormat("\"msg\":\"{0}\",", getlast("msg")); } //客户端须要知道购买列表是否变更 if (keys.Contains("buy")) { builder.AppendFormat("\"buy\":\"{0}\",", getlast("buy")); } //类推各类监听....... //移除最后“,” if (builder.Length > 1) { builder.Remove(builder.Length - 1, 1); } builder.Append("}"); return Content(builder.ToString()); } public ContentResult msg(data ms) { InsertCache(ms, "msg"); return Content("ok"); } public ContentResult buy(data buy) { InsertCache(buy, "buy"); return Content("ok"); } private void InsertCache(data d, string cacheKey) { //使用时间设置最后更新量 d.time = DateTime.Now.ToString("yyyyMMddhhmmssffff"); //获取存储的值 List<data> ls = HttpRuntime.Cache.Get(cacheKey) as List<data>; //判断是否为空 if (ls == null) { ls = new List<data>(); HttpRuntime.Cache.Insert(cacheKey, ls); } //添加到集合 ls.Insert(0, d); //移除大于这个数 if (ls.Count > 10) ls.RemoveRange(10, ls.Count - 10); } public JsonResult GetList(string key) { if (string.IsNullOrEmpty(key)) return Json(null, JsonRequestBehavior.AllowGet); return Json(HttpRuntime.Cache.Get(key) as List<data>, JsonRequestBehavior.AllowGet); } public JsonResult GetCache() { return Json(new { p1 = HttpRuntime.Cache.EffectivePercentagePhysicalMemoryLimit, p2 = HttpRuntime.Cache.EffectivePrivateBytesLimit }, JsonRequestBehavior.AllowGet); } } //定义一个数据存储介质 public class data { public string user { get; set; } public string msg { get; set; } public string time { get; set; } } }