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

Blazor Server中如何优先处理最新地图请求并跳过旧等待任务

解决方案:只处理最新地图钉加载请求

核心思路是维护一个仅保留最新请求的队列机制,确保当前任务完成后只处理最新的有效请求,旧的等待请求直接标记完成,无需执行数据库查询。

关键实现逻辑

  • 用SemaphoreSlim保证同一时间仅执行一个加载任务
  • 用TaskCompletionSource跟踪每个请求的完成状态,新请求到来时直接终结旧的等待请求
  • 进入执行阶段前,验证当前请求是否为最新,无效请求直接返回

代码实现示例

public class MapPinLoader
{
    private readonly SemaphoreSlim _executionLock = new SemaphoreSlim(1, 1);
    private readonly object _stateLock = new object();
    private TaskCompletionSource<bool>? _latestPendingRequest;

    public async Task HandleMapViewChangeAsync(MapViewBounds newBounds)
    {
        // 创建当前请求的完成源
        var currentRequestTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

        lock (_stateLock)
        {
            // 终结之前的最新等待请求(让旧请求的调用方直接完成)
            _latestPendingRequest?.TrySetResult(true);
            // 将当前请求设为最新
            _latestPendingRequest = currentRequestTcs;
        }

        try
        {
            await _executionLock.WaitAsync();

            lock (_stateLock)
            {
                // 如果当前请求已经不是最新的,直接退出,不执行查询
                if (_latestPendingRequest != currentRequestTcs)
                {
                    return;
                }
            }

            // 执行耗时的数据库查询
            var newPins = await FetchPinsFromDbAsync(newBounds);

            // Blazor中更新UI需确保在主线程
            await UpdateMapPinsInUiAsync(newPins);
        }
        finally
        {
            lock (_stateLock)
            {
                // 标记当前请求完成
                currentRequestTcs.TrySetResult(true);
                // 如果处理过程中又有新请求进来,下一次WaitAsync会自动处理最新的
            }
            _executionLock.Release();
        }
    }

    // 模拟数据库查询逻辑
    private async Task<List<MapPin>> FetchPinsFromDbAsync(MapViewBounds bounds)
    {
        // 替换为你的实际查询代码,耗时4-10秒
        await Task.Delay(6000);
        return new List<MapPin>();
    }

    // 模拟Blazor UI更新逻辑
    private async Task UpdateMapPinsInUiAsync(List<MapPin> pins)
    {
        // 在Blazor组件中需调用InvokeAsync确保线程安全
        // await InvokeAsync(() => { /* 更新组件内的地图钉集合 */ });
    }
}

// 地图视图边界模型
public class MapViewBounds
{
    public double MinLatitude { get; set; }
    public double MaxLatitude { get; set; }
    public double MinLongitude { get; set; }
    public double MaxLongitude { get; set; }
}

// 地图钉模型
public class MapPin
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public string Label { get; set; } = string.Empty;
}

使用说明

  1. 在Blazor组件中实例化MapPinLoader(可通过依赖注入注册为单例/作用域服务)
  2. 用户滚动/缩放地图时,调用HandleMapViewChangeAsync并传入当前地图边界
  3. 旧的等待请求会自动被终结,无需等待无效的查询结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 16:30:23