我一直在修补 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();
}
}
答案 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
点。除非当前任务完成,否则它不会让下一个任务执行。这保证您上次执行的任务不会由于竞争条件而被某些前任覆盖。