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

ASP.NET Razor页面大数据加载缓慢,求推荐优化方案

针对你遇到的Razor页面加载慢的问题,结合你的代码情况,给你几个实用的解决方向:

一、先优化服务器端数据处理逻辑(最立竿见影)

你的嵌套循环里最耗时的是ActivePallets.FirstOrDefault(a => a.GetLocation() == s.key),因为每次查找都是遍历整个数组,数据量大的时候这个操作会被执行成千上万次,直接拖慢速度。

  • 把ActivePallets转换成字典,用GetLocation()的结果作为键,将查找操作从O(n)降为O(1):
    // 替换原来的Pallet[] ActivePallets = ViewBag.ActivePalletArr;
    var activePalletLookup = ((Pallet[])ViewBag.ActivePalletArr).ToDictionary(a => a.GetLocation());
    
    后续Select里替换FirstOrDefault:
    PalletItem = activePalletLookup.TryGetValue(s.key, out var pallet) ? pallet : null,
    
  • 提前计算Zone的统计数据,避免在视图里实时计算:
    在bindata的投影里直接加入统计字段,视图里直接取用即可:
    var bindata = Model.GroupBy(x => x.description)
        .Select(x => new
        {
            Zone = x.Key.description,
            PalletCount = x.Count(s => activePalletLookup.ContainsKey(s.key)),
            TotalCount = x.Count(),
            Location = x.Select(s => 
            {
                activePalletLookup.TryGetValue(s.key, out var pallet);
                var aging = pallet != null ? (DateTime.Now - pallet.CreatedOn).Days : 0;
                return new
                {
                    PalletItem = pallet,
                    Aging = aging,
                    BIN = s.key,
                    LOCATION = s.value
                };
            })
        })
        .OrderByDescending(x => x.Zone)
        .ToArray();
    
  • 简化嵌套Select,把两次投影合并成一次,减少中间匿名对象的创建开销。

二、实现点击Zone再加载对应数据(彻底减少首次加载量)

你之前想的点击加载思路是对的,核心是用AJAX从服务器获取对应Zone的HTML片段:

  1. 在Razor Page中添加请求处理Handler:
    在页面对应的.cs文件中添加:
    public IActionResult OnGetLoadZoneDetails(string zone)
    {
        var model = (ValueDataSet[])Model;
        var activePallets = ((Pallet[])ViewBag.ActivePalletArr).ToDictionary(a => a.GetLocation());
        var zoneData = model.Where(x => x.description == zone)
            .Select(s => 
            {
                activePallets.TryGetValue(s.key, out var pallet);
                var aging = pallet != null ? (DateTime.Now - pallet.CreatedOn).Days : 0;
                return new
                {
                    PalletItem = pallet,
                    Aging = aging,
                    BIN = s.key,
                    LOCATION = s.value
                };
            });
        return Partial("_ZoneDetails", zoneData);
    }
    
  2. 创建Partial View(_ZoneDetails.cshtml):
    把原来渲染BIN的循环代码单独抽出来:
    @model IEnumerable<dynamic>
    @foreach (var bin in Model)
    {
        var order = bin.PalletItem?.ContainerItem?.OrderItem;
        <div class="binlocation @(bin.Aging > 12 ? "aging2" : bin.Aging > 0 ? "aging1" : "")">
            @bin.BIN (@bin.Aging)
            <div>
                <small>@(bin.PalletItem?.LicensePlate)</small>
                <small>@(order != null ? $"<a href=\"/order/edit/{order.ItemKey}\" target=\"_blank\">{order.OrderNumber}</a>" : "")</small>
            </div>
        </div>
    }
    
  3. 修改主页面的JavaScript逻辑:
    替换原来的toggledetails函数,实现点击加载:
    <script>
        function toggledetails(zoneIdx, zoneName) {
            const targetDiv = document.querySelector(`.toggledetail_${zoneIdx}`);
            if (targetDiv.style.display === 'none') {
                // 避免重复加载
                if (targetDiv.innerHTML.trim() === '') {
                    fetch(`?handler=LoadZoneDetails&zone=${encodeURIComponent(zoneName)}`)
                        .then(response => response.text())
                        .then(html => {
                            targetDiv.innerHTML = html;
                            targetDiv.style.display = 'block';
                        });
                } else {
                    targetDiv.style.display = 'block';
                }
            } else {
                targetDiv.style.display = 'none';
            }
        }
    </script>
    
    同时修改h5的点击参数,传入Zone名称:
    <h5><b onclick="toggledetails(@(zoneidx), '@item.Zone')" style="cursor:pointer;">@item.Zone (@item.PalletCount / @item.TotalCount)</b></h5>
    
    这样首次加载只渲染Zone标题,点击后才加载对应BIN的内容,大幅降低首次加载耗时。

三、其他辅助优化

  • 避免在视图循环内创建新对象:比如把new OrderItem()换成null,视图里用@(order?.OrderNumber ?? ""),减少不必要的对象创建。
  • 缓存系统时间:在服务器端开头定义var now = DateTime.Now;,后续计算Aging都用这个变量,避免多次获取系统时间。
  • 服务器端缓存:如果数据不是实时更新的,可以用MemoryCache缓存bindata或Zone数据,减少重复计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:57:09