You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

每200ms发起10次Ajax Get调用,运行数分钟后卡顿延迟求助

解决高频Ajax请求导致的页面卡顿问题

嘿,我完全懂你现在的困扰——10个高频Ajax请求一开始跑得顺风顺水,过几分钟就开始卡顿,网络请求也越来越慢。这本质是高频请求叠加带来的浏览器并发连接限制、服务器压力过载和DOM重复操作冗余导致的,咱们一步步来优化:


1. 优先合并请求,减少HTTP连接开销

你现在每个模块都用独立请求,200ms一次的话,每秒要发起50次请求!而浏览器对同一域名的并发连接数通常限制在6-8个,剩下的请求都会排队等待,时间一长队列就会越积越长,直接导致卡顿。

后端改造:合并接口返回所有数据

把10个独立的JsonResult合并成一个接口,一次性返回所有模块的数据集:

public JsonResult GetAllMarketData() 
{
    var allMarketData = new 
    {
        Indices = SinkClass.IndicesList,
        Energy = SinkClass.EnergyList,
        Oil = SinkClass.OilList,
        Cots = SinkClass.CotsList,
        Agri = SinkClass.AgriList,
        Intra = SinkClass.IntraList,
        PGold = SinkClass.PGoldList,
        Pagri = SinkClass.PagriList,
        Finan = SinkClass.FinanList,
        Data2 = SinkClass.Data2List // 对应原来的showdata2数据源
    };
    return Json(allMarketData, JsonRequestBehavior.AllowGet);
}

前端改造:单定时器+统一处理

只保留一个定时器,请求一次拿到所有数据后,再分模块处理:

$(document).ready(function () {
    // 页面加载后发起第一次请求
    setTimeout(fetchAllMarketData, 0);
});

function fetchAllMarketData() {
    showTime();
    $.ajax({
        url: "../Employees/GetAllMarketData",
        type: "Get",
        async: true,
        cache: false, // 实时数据禁用缓存,避免拿到旧数据
        dataType: 'json',
        success: function (allData) {
            // 分模块处理数据
            processIndicesData(allData.Indices);
            processEnergyData(allData.Energy);
            processOilData(allData.Oil);
            // ...依次处理剩下的模块
            
            // 上一次请求完成后,再延迟200ms发起下一次(避免请求堆积)
            setTimeout(fetchAllMarketData, 200);
        },
        error: function (msg) { 
            console.error('数据获取失败:', msg);
            // 请求失败时延长间隔,减少服务器压力
            setTimeout(fetchAllMarketData, 500);
        }
    });
}

// 把原来的showindices拆成独立的数据处理函数
function processIndicesData(data) {
    $.each(data, function (index) {
        const contractId = data[index].Contract;
        let rowEl = document.getElementById(contractId);

        if (!rowEl) {
            // 新行插入DOM,用模板字符串更简洁
            $('#indices tbody').append(`
                <tr class='child' id="${contractId}" onclick='MakeCellEditable(this)'>
                    <td class='Symm' id='sss'> <b>${contractId}</b> </td>
                    <td class='BVol'>${data[index].BidVolume}</td>
                    <td class='bid'>${data[index].Bid}</td>
                    <td class='ASK'>${data[index].Ask}</td>
                    <td class='AVol'>${data[index].AskVolume}</td>
                    <td class='LAST'>${data[index].last_}</td>
                    <td class='VOLUME'>${data[index].volume_}</td>
                    <td class='totalT'>${data[index].Total_Volume}</td>
                    <td class='hig'>${data[index].High}</td>
                    <td class='lw'>${data[index].Low}</td>
                    <td class='change'>${data[index].Change}</td>
                    <td class='changeP'>${data[index].Change_Per}</td>
                    <td class='open'>${data[index].Open}</td>
                    <td class='closeP'>${data[index].Close}</td>
                </tr>
            `);
            rowEl = document.getElementById(contractId);
        }

        // 缓存当前行的所有需要操作的元素,避免重复查询DOM
        const bVolEl = rowEl.querySelector(".BVol");
        const bidEl = rowEl.querySelector(".bid");
        const askEl = rowEl.querySelector(".ASK");
        const aVolEl = rowEl.querySelector(".AVol");
        const lastEl = rowEl.querySelector(".LAST");
        // ...缓存其他需要更新的元素

        // 处理BidVolume
        if (bVolEl.textContent == 0) bVolEl.textContent = "";
        if (bVolEl.textContent !== data[index].BidVolume.toString()) {
            bVolEl.textContent = data[index].BidVolume;
        }

        // 处理Bid(优化颜色逻辑)
        if (bidEl.textContent == 0) bidEl.textContent = "";
        if (bidEl.textContent !== data[index].Bid.toString()) {
            bidEl.style.backgroundColor = Number(bidEl.textContent) > data[index].Bid ? "yellow" : "palegreen";
            bidEl.textContent = data[index].Bid;
        } else {
            bidEl.style.backgroundColor = "white";
        }

        // ...按照同样的逻辑处理其他字段,用缓存的元素操作
    });
}

2. 优化DOM操作,减少重绘重排

原来的代码里每次更新都用getElementsByClassName重复查询DOM,这是非常消耗性能的——DOM查询是浏览器最耗时的操作之一。

核心优化点:

  • 缓存当前行的所有需要操作的元素,只查询一次DOM
  • 用textContent代替innerHTML(如果只是更新文本,textContent更高效且安全)
  • 避免频繁修改元素样式,尽量批量操作

3. 后端额外优化建议

  • 启用响应压缩:在ASP.NET中开启Gzip/Brotli压缩,大幅减少JSON数据的传输大小
  • 增量返回数据:只返回有变化的字段,比如后端记录每个数据的更新时间,只返回上次请求后变化的数据
  • 优化数据源获取:如果SinkClass是从数据库/外部API拉取数据,要确保数据获取的效率,比如用内存缓存缓存非实时字段,减少数据库查询次数

4. 临时缓解方案(如果无法合并请求)

如果暂时不能合并接口,至少给每个请求加请求锁,避免同一时间多个相同请求并发:

let isIndicesRequesting = false;
function showindices() {
    // 如果上一次请求还没完成,直接返回
    if (isIndicesRequesting) return;
    isIndicesRequesting = true;

    showTime();
    $.ajax({
        url: "../Employees/GetIndicesJsonObject",
        type: "Get",
        async: true,
        cache: false,
        dataType: 'json',
        success: function (data) {
            // 处理数据...
            isIndicesRequesting = false;
        },
        error: function (msg) {
            isIndicesRequesting = false;
        }
    });
}

内容的提问来源于stack exchange,提问作者Muhammad Shoaib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:42