Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 6966|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-21 09:59:06 | 显示全部楼层 |阅读模式

    一、背景

      开发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全部完毕的情况下才会发送请求。

    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);
             }
         });
    });
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-5 06:01 , Processed in 0.060161 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表