【Javascript】解决Ajax轮询形成的线程阻塞问题(过渡方案)

1、背景javascript

  开发Web平台时,常常会须要定时向服务器轮询获取数据状态,而且一般不只只开一个轮询,而是根据业务须要会产生数个轮询。这种状况下,性能低下的Ajax长轮询已经不能知足需求,频繁的访问还会形成线程阻塞。最优的解决方案固然是用Websocket,采用服务器推送的方式来减小频繁开关链接形成的开销。可是Websocket对于我来讲还只是个新事物,在未完成论证的状况下不能直接开发完就上,所以只好采用过渡方案,使用队列的方式,暂时优化多AJax长轮询的状况下形成的线程阻塞问题。java

  我所用的Web平台框架是国产开源的DWZ框架。该框架不使用经典的iframe模式,全部的视图、数据访问都是经过Ajax获取后在前台进行加载渲染,页面迁移跳转极少,所以本质上来讲基于DWZ框架的网页都是Single Page页面。在这种状况下,除了长轮询外,还会根据用户的操做产生其它Ajax连接。这就要求在优化的同时,还要保证用户操做的优先度。毕竟长轮询只是后台默认执行的操做,对用户的体验影响不大;但用户的操做由于长轮询形成延迟的话,用户体验就十分糟糕。jquery

  此外,我还发现处理这些Ajax轮询所用的Controller是MVC默认的,然而这些Controller不支持异步处理请求操做,在多个请求访问时,新请求必须等待旧请求完成后才能继续下去。ajax

  综上所述,优化Ajax轮询形成的线程阻塞问题的过渡方案中,有如下两点要求:json

    1.使用Ajax队列的方式,不推倒现有的技术方案,在原有的基础上快速修改。服务器

    2.在Ajax队列优化过程当中,必须保证用户操做的优先度,保证用户操做的及时响应。框架

    3.替换原有只支持同步Action的Controller,使用可支持异常Action的Controller。异步

2、前台代码解析socket

     整体思路是:性能

  1.重写jquery既有的ajax方法,将全部调用该方法的ajax所有注册到自定义的ajax程序池中。

  2.自定义ajax程序池分全局和非全局两类,长轮询发起的ajax为非全局,用户发起的ajax为全局。

  3.排队执行两个程序池中的请求,一个请求完成后才继续执行下一个,而非异步将全部ajax同时发起请求。

  4.全局ajax的优先度高,若是当前正在执行非全局ajax且有未发起的全局ajax,则中止正在执行的非全局ajax,优先发送全局ajax。

  5.非全局ajax只有在全局ajax所有完毕的状况下才会发送请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 全部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);
         }
     });
});
相关文章
相关标签/搜索