触发多个异步任务并仅更新最新任务的结果

时间:2021-01-29 11:57:19

标签: c# async-await blazor

我一直在修补 Blazor,但遇到了 async/await 问题。我添加了一个搜索输入字段,它触发一个异步操作,当用户开始输入时,该操作将搜索结果返回给用户。问题是异步任务以错误的顺序完成。触发的第一个任务会返回并使后面已经完成的任务的结果无效。

我想出了一个涉及跟踪任务的解决方案,但这是正确的做法还是我的做法错误?

我目前的解决方案如下:

        private List<Task> runningTasks = new List<Task>();

        protected async Task OnSearchTermChanged(ChangeEventArgs e)
        {
            SearchTerm = e.Value.ToString();

            if(SearchTerm.Length >= 3)
            {
                SearchResult = null;
                var task = AdService.SearchUsers(SearchTerm);
                runningTasks.Add(task);
                var result = await task;

                if(task == runningTasks.Last())
                {
                    SearchResult = result;
                }
            }
            else
            {
                SearchResult ??= new List<AdUser>();
                SearchResult.Clear();
            }
        }

2 个答案:

答案 0 :(得分:7)

对于这种场景,我使用我所谓的“异步上下文”(可能是一个非常糟糕的名字,因为如今“上下文”可能意味着很多东西)。您只需要某种唯一值(new object() 就足够了),将此值捕获到 await 之前的局部变量中,然后在 await 之后进行比较。如果它们不匹配,那么该代码就会知道它不再是当前的。

private object _context;

protected async Task OnSearchTermChanged(ChangeEventArgs e)
{
  SearchTerm = e.Value.ToString();

  if (SearchTerm.Length >= 3)
  {
    var localContext = _context = new object();
    SearchResult = null;
    var task = AdService.SearchUsers(SearchTerm);
    var result = await task;

    if (localContext == _context)
    {
      SearchResult = result;
    }
  }
  else
  {
    _context = null;
  }
}

答案 1 :(得分:0)

一般来说,有顺序和并行组合(用于异步操作)。如果你希望事情以某种特定的顺序发生(你确实想要),你就不能并行运行。看下面的代码:

var enumerableOfTasks = ... // whatever enumerable of tasks in some desired order
foreach (var task in enumerableOfTasks) await task;

...所有的魔法都发生在 await task 点。除非当前任务完成,否则它不会让下一个任务执行。这保证您上次执行的任务不会由于竞争条件而被某些前任覆盖。

相关问题