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


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);

        }

    });

});

时间: 2024-07-31 00:56:27

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

Ajax轮询——“定时的通过Ajax查询服务端”

Ajax轮询——"定时的通过Ajax查询服务端". 概念: 轮询(polling):客户端按规定时间定时像服务端发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 百闻不如一见,来段代码相信你一看就明白 //为了让同学们都明白,我用了最简单的实现方法,同学们懂了原理后可以自行衍生: Reception.html //前端代码 <html> <head> <title></title> <script src="

闲话ajax,例ajax轮询,ajax上传文件

引语:ajax这门技术早已见怪不怪了,我本人也只是就自己真实的经验去总结一些不足道的话.供不是特别了解的朋友参考参考! 本来早就想写一篇关于ajax的文章的,但是前段时间一直很忙,就搁置了,趁着元旦放假,赶紧补上吧! ajax的出现,可以出给用户带来了很好的体验,证据如下: 1.感觉:以前要给用户呈现新的内容,就必须要刷新当前页面,结果往往是这样:用户看着看着,唰...,然后又重头看起,我那个去,这谁受得了; 自从有了ajax后,就是这样的,用户关注哪一块,变化哪一块,我们就更新那一块,完全看不

ajax轮询请求实现源码分享

ajax轮询请求状态是ajax学习中非常重要的也是必须掌握的知识点,今天就和大家一起来分享一下这部分内容,一起来看看吧.      这里要实现的功能是:通过扫码微信公众号带参数的二维码,来登录网站.      但很明显,如果ajax不间断的请求服务器,这样会加重服务器的负荷,所以本例采用的是js的setInterval来周期性调用执行一个ajax函数来来向服务器请求数据,但请求成功或者请求一定次数后还未成功时用clearinterval函数清空计时器. 代码和注释如下:(后端采用thinkPHP

long poll、ajax轮询和WebSocket

websocket 的认识深刻有木有.所以转到我博客里,分享一下.比较喜欢看这种博客,读起来很轻松,不枯燥,没有布道师的阵仗,纯粹为分享.废话这么多了,最后再赞一个~ WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 1.1 和 keep-alive ,把多个HTTP请求合并为一个,但是 Websocket 其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说

ajax轮询与长轮询

  刚刚网了关于轮询的知识,必须拿到自己这里来做个备份了! 其实以前用ajax轮询做个及时数据更新的,只是当时做了不知道那个就是轮询. 首先我们什么时候会想到用轮询技术呢? 一般而言,最多的是及时信息更新,比如一个商城活动,参与人数的实时更新等,也还有人用来做过聊天室的,但是哈,轮询技术问题还是很多的,频繁的请求的服务器,服务器会把IP给你列入非白名单里,让你无法请求服务器.所以做及时的我还是建议用websocket 建立长连接. 其次小杨用一位老师的原话来讲解一下ajax轮询技术: 一.Aja

Ajax轮询请求

Ajax轮询请求 什么是轮询? 轮询(polling):客户端按规定时间定时向服务端发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. Ajax轮询需要服务器有很快的处理速度与快速响应. Ajax轮询实现 Ajax轮询原理 客户端是按照规定时间(这个时间由你设定,此处默认为1秒)像服务端发送请求,前一次请求完成后,无论有无结果返回,一秒之后下一次请求又会发出.这就叫做Ajax轮询. <script> $(function(){ var code,status; function g

ajax轮询session阻塞问题

近来读了几篇关于ASP.NET下Session机制的文章,结合自己的实际应用,有点感想: 在ASP.NET的Session的默认机制下,对同一个SessionID下的用户请求ASP.NET的Session数据的操作会引起排他锁,假设在同一个SessionID下有多个用户同时请求Session数据的话,就会出现很大的延迟现象.把Session的信息设置为ReadOnly,将不会在导致排他锁的出现.但是,只读Session'数据的操作还是要等待对Session的读写操作引起的排他锁的释放. 因此在不

COMET探索系列二【Ajax轮询复用模型】

COMET探索系列二[Ajax轮询复用模型] 写在前面:Ajax轮询相信大家都信手拈来在用,可是有这么一个问题,如果一个网站中同时有好多个地方需要用到这种轮询呢?就拿我们网站来说,有一个未读消息数提醒.还有一个时实时加载最新说说.昨天又加了一个全网喊话,以后还会要有类似功能添加是肯定的,难道要为每个功能都创建一个独立的轮询?要知道轮询请求中有大半是无用,会对服务器资源和宽带造成巨大的浪费.因此在页面中每增加一个轮询点,对服务器的压力及宽带浪费都将成倍的增长.再考虑一个情况,如果当前网页中需要的不

Ajax轮询消息自动提示(消息盒子)

经过一下午写了个消息盒子的例子,用的是ajax方式轮询读取,没有用到后台自动“推”数据的方式,效果良好. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="mainTalk.aspx.cs" Inherits="wj_test.Talk.mainTalk" %> <!DOCTYPE html PUBLIC "-//W3C//DTD X