【Javascript】解决Ajax轮询造成的线程阻塞问题(过渡方案)
一、背景
开发Web平台时,经常会需要定时向服务器轮询获取数据状态,并且通常不仅只开一个轮询,而是根据业务需要会产生数个轮询。这种情况下,性能低下的Ajax长轮询已经不能满足需求,频繁的访问还会造成线程阻塞。最优的解决方案当然是用Websocket,采用服务器推送的方式来减少频繁开关连接造成的开销。但是Websocket对于我来说还只是个新事物,在未完成论证的情况下不能直接开发完就上,因此只好采用过渡方案,使用队列的方式,暂时优化多AJax长轮询的情况下造成的线程阻塞问题。
我所用的Web平台框架是国产开源的DWZ框架。该框架不使用经典的iframe模式,所有的视图、数据访问都是通过Ajax获取后在前台进行加载渲染,页面迁移跳转极少,因此本质上来说基于DWZ框架的网页都是Single Page页面。在这种情况下,除了长轮询外,还会根据用户的操作产生其它Ajax链接。这就要求在优化的同时,还要保证用户操作的优先度。毕竟长轮询只是后台默认执行的操作,对用户的体验影响不大;但用户的操作因为长轮询造成延迟的话,用户体验就十分糟糕。
此外,我还发现处理这些Ajax轮询所用的Controller是MVC默认的,然而这些Controller不支持异步处理请求操作,在多个请求访问时,新请求必须等待旧请求完成后才能继续下去。
综上所述,优化Ajax轮询造成的线程阻塞问题的过渡方案中,有以下两点要求:
1.使用Ajax队列的方式,不推倒现有的技术方案,在原有的基础上快速修改。
2.在Ajax队列优化过程中,必须保证用户操作的优先度,保证用户操作的及时响应。
3.替换原有只支持同步Action的Controller,使用可支持异常Action的Controller。
二、前台代码解析
总体思路是:
1.重写jquery既有的ajax方法,将所有调用该方法的ajax全部注册到自定义的ajax程序池中。
2.自定义ajax程序池分全局和非全局两类,长轮询发起的ajax为非全局,用户发起的ajax为全局。
3.排队执行两个程序池中的请求,一个请求完成后才继续执行下一个,而非异步将所有ajax同时发起请求。
4.全局ajax的优先度高,如果当前正在执行非全局ajax且有未发起的全局ajax,则停止正在执行的非全局ajax,优先发送全局ajax。
5.非全局ajax只有在全局ajax全部完毕的情况下才会发送请求。
// 所有ajax请求都注册到DNE.LoadingAjax的ajax程序池中,排队发起请求,ajax结束时删除.
DNE.LoadingAjax = {
jqAjax: $.ajax,
requests: {}, // ajax对象集合
globalAjaxPool: [], // 全局ajax程序池
unglobalAjaxPool: [], // 非全局ajax程序池
interval: null, // ajax循环定时器
runningType: null, // 正在运行的Ajax类型 1:全局 2:非全局
runningId: null,// 正在运行的AjaxId
// 注册Ajax到程序池中
PushAjaxPool: function (request, options) {
var urlComplete = request.complete;
var requests = this.requests;
var id = (request.tabId) ? request.tabId : request.url; // 请求结束时,删除ajax对象
request.complete = this.deleteAjax(urlComplete, id); // 将请求放到ajax程序池中
var requestObj = {
id: id,
request: request,
options: options
}; // 如果是获取json数据的请求,则放入程序池中,如果是获取Js或图片等资源的请求,则直接执行
if (requestObj.request.dataType == "json") {
if (request.global) {
// 如果是全局ajax
this.globalAjaxPool.push(requestObj);
} else {
// 如果不是全局ajax
this.unglobalAjaxPool.push(requestObj);
}
} else {
var loadingAjax = DNE.LoadingAjax;
loadingAjax.runAjax(requestObj);
} if (!this.interval) {
this.interval = window.setInterval(function () { var loadingAjax = DNE.LoadingAjax; // 如果当前有全局Ajax未运行,则停止正在运行的非全局Ajax
if (loadingAjax.runningType != 1 && loadingAjax.globalAjaxPool.length > 0) {
if (loadingAjax.runningType == 2 && loadingAjax.runningId) {
loadingAjax.ajaxAbort(id);
} // 运行最开头的全局Ajax
var reqObj = loadingAjax.globalAjaxPool.shift();
loadingAjax.runAjax(reqObj); } else {
// 如果当前没有正在执行的Ajax,并且非全局Ajax程序池中有对象
if (loadingAjax.runningType == null && loadingAjax.unglobalAjaxPool.length > 0) { // 运行最开头的非全局Ajax
var reqObj = loadingAjax.unglobalAjaxPool.shift();
loadingAjax.runAjax(reqObj);
}
}
}, 100);
}
},
// 删除Ajax
deleteAjax: function (urlComplete, id) {
if (urlComplete && typeof (urlComplete) == "function") {
urlComplete();
} var loadingAjax = DNE.LoadingAjax;
if (loadingAjax.requests[id]) {
delete loadingAjax.requests[id];
} // 如果程序池中已无请求,则清空ajax循环定时器
if (loadingAjax.globalAjaxPool.length <= 0 && loadingAjax.unglobalAjaxPool.length <= 0) {
loadingAjax.interval = null;
} // 如果当前请求结束,则重置正在运行的Ajax类型及AjaxId
loadingAjax.runningType = null;
loadingAjax.runningId = null;
},
// 执行Ajax
runAjax: function (reqObj) {
var jqXHR = this.jqAjax(reqObj.request, reqObj.options);
this.requests[reqObj.id] = jqXHR;
},
// 停止Ajax
ajaxAbort: function (id) {
var jqXHR = this.requests[id];
if (jqXHR) {
jqXHR.abort();
delete this.requests[id];
}
}
};
$(function () {
$.extend({
ajax: function (url, options) {
// 所有ajax都注册到ajax程序池中
DNE.LoadingAjax.PushAjaxPool(url, options);
}
});
});
三、后台代码解析(待续)
【Javascript】解决Ajax轮询造成的线程阻塞问题(过渡方案)的更多相关文章
- WebSocket和long poll、ajax轮询的区别,ws协议测试
WebSocket和long poll.ajax轮询的区别,ws协议测试 WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连 ...
- Ajax轮询以及Comet模式—写在Servlet 3.0发布之前(转)
2008 年的夏天,偶然在网上闲逛的时候发现了 Comet 技术,人云亦云间,姑且认为它是由 Dojo 的 Alex Russell 在 2006 年提出.在阅读了大量的资料后,萌发出写篇 blog ...
- WebSocket原理及与http1.0/1.1 long poll和 ajax轮询的区别【转自知乎】
一.WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)首先HTTP有1.1和1.0之说,也就是所谓的ke ...
- ajax轮询与长轮询
刚刚网了关于轮询的知识,必须拿到自己这里来做个备份了! 其实以前用ajax轮询做个及时数据更新的,只是当时做了不知道那个就是轮询. 首先我们什么时候会想到用轮询技术呢? 一般而言,最多的是及时信息 ...
- 闲话ajax,例ajax轮询,ajax上传文件[开发篇]
引语:ajax这门技术早已见怪不怪了,我本人也只是就自己真实的经验去总结一些不足道的话.供不是特别了解的朋友参考参考! 本来早就想写一篇关于ajax的文章的,但是前段时间一直很忙,就搁置了,趁着元旦放 ...
- Ajax轮询——“定时的通过Ajax查询服务端”
Ajax轮询——"定时的通过Ajax查询服务端". 概念: 轮询(polling):客户端按规定时间定时像服务端发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 百闻 ...
- Ajax轮询——定时的通过Ajax查询服务端
概念:轮询(polling):客户端按规定时间定时向服务端发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. test.html //前端代码 <html> <h ...
- Ajax轮询请求
Ajax轮询请求 什么是轮询? 轮询(polling):客户端按规定时间定时向服务端发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. Ajax轮询需要服务器有很快的处理速度与快速响应. ...
- long poll、ajax轮询和WebSocket
websocket 的认识深刻有木有.所以转到我博客里,分享一下.比较喜欢看这种博客,读起来很轻松,不枯燥,没有布道师的阵仗,纯粹为分享.废话这么多了,最后再赞一个~ WebSocket是出的东西(协 ...
随机推荐
- RPC
那是N年前的一天,老王在看一本讲java的技术书(可惜忘了叫啥名字了),突然看到有一章讲RMI的,立马就觉得很好奇.于是乎,就按书上所讲,写了demo程序.当时也就只知道怎么用,却不知道什么原理.直到 ...
- 【CF 710F】String Set Queries
在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...
- 调出CorelDRAW新工具栏的方法
CorelDRAW中允许用户自定义调出新工具栏.当使用CorelDRAW软件某一工具.命令频率较高时,对于不同的设计师来说会有不同的习惯的,有的喜欢中规中矩的按部就班的操作,有的则喜欢用右键快速调用, ...
- Python3 基本数据类型
Python中的变量不需要声明,每个变量使用前必须赋值,变量赋值后才会被创建,在Python中变量就是变量,它没有类型.我们所说的"类型"是变量所指的内存中对象的类型. 等号(=) ...
- [转]win 10 开始菜单(Win 7风格)增强工具 StartIsBack++ v1.3.4 简体中文特别版
Windows10开始菜单增强工具StartIsBack++现已更新至v1.3.4,最近主要修复在Win10周年更新版上恢复睡眠后任务栏通知中心按钮消失的问题.升级版对StartIsBack+全新构建 ...
- COGS396. [网络流24题]魔术球问题(简化版
问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平 ...
- IntelliJ IDEA For Mac 快捷键
Mac键盘符号和修饰键说明 ⌘ Command ⇧ Shift ⌥ Option ⌃ Control ↩︎ Return/Enter ⌫ Delete ⌦ 向前删除键(Fn+Delete) ↑ 上箭头 ...
- wpf 客户端 添加qq客服咨询
使用qq推广 站点:http://shang.qq.com/v3/widget.html 复制里面的html代码: <a target=" src="http://wpa.q ...
- linux下centos的网络连接
- 改进你的WordPress导航菜单 —— 输出标题描述
在WordPress 3.0中增加了自定义菜单功能,如果你在WordPress后台(外观>菜单)创建一个菜单,你可以在主题中使用wp_nav_menu()函数来显示这些菜单.但是像图中这种带描述 ...