如果收到新请求,如何取消以前的任务?
How to cancel previous Task if new request recieved?
我会尽量简化这里的情况,使之更加简洁明了。所以,我正在开发一个 WinRT 应用程序,用户在 TextBox
中输入文本,并在 2 秒后在其 TextChanged
事件中输入文本,我需要制作一个远程请求根据用户文本获取数据。
现在用户输入文本并且 Web 请求已初始化,但用户立即写入另一个术语。所以,我需要取消第一个网络请求并触发新的请求。
考虑以下作为我的代码:
private CancellationTokenSource cts;
public HomePageViewModel()
{
cts = new CancellationTokenSource();
}
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
//Cancel previous request before making new one
//GetMembers() is using simple HttpClient to PostAsync() and get response
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
}
我知道 CancellationToken
在这里发挥了作用,但我不知道是如何发挥作用的。
我会像这样实现 GetMembers
方法:
private async Task<List<Member>> GetMembers(int id, CancellationToken token)
{
try
{
token.ThrowIfCancellationRequested();
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
{
response = await client.PostAsync(new Uri("http://apiendpoint"), content)
.AsTask(token);
}
token.ThrowIfCancellationRequested();
// Parse response and return result
}
catch (OperationCanceledException ocex)
{
return null;
}
}
剩下的只是调用 cts.Cancel()
方法并在处理程序中每次调用 GetMembers
之前创建一个新的 CancellationTokenSource
实例。当然,正如@Russell Hickey 提到的,cts
应该是全局的。 (如果这个 class 有多个实例并且你总是想在调用这个处理程序时取消 GetMembers
方法,甚至是静态的。通常我还有一个 class 来包装结果和有一个额外的 属性 IsSuccessful
来区分真正的 null
结果和失败的操作。
你已经差不多明白了。核心思想是单个CancellationTokenSource
只能取消一次,所以每次操作都要新建一个
private CancellationTokenSource cts;
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
// If there's a previous request, cancel it.
if (cts != null)
cts.Cancel();
// Create a CTS for this request.
cts = new CancellationTokenSource();
try
{
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
}
catch (OperationCanceledException)
{
// This happens if this operation was cancelled.
}
}
我会尽量简化这里的情况,使之更加简洁明了。所以,我正在开发一个 WinRT 应用程序,用户在 TextBox
中输入文本,并在 2 秒后在其 TextChanged
事件中输入文本,我需要制作一个远程请求根据用户文本获取数据。
现在用户输入文本并且 Web 请求已初始化,但用户立即写入另一个术语。所以,我需要取消第一个网络请求并触发新的请求。
考虑以下作为我的代码:
private CancellationTokenSource cts;
public HomePageViewModel()
{
cts = new CancellationTokenSource();
}
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
//Cancel previous request before making new one
//GetMembers() is using simple HttpClient to PostAsync() and get response
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
}
我知道 CancellationToken
在这里发挥了作用,但我不知道是如何发挥作用的。
我会像这样实现 GetMembers
方法:
private async Task<List<Member>> GetMembers(int id, CancellationToken token)
{
try
{
token.ThrowIfCancellationRequested();
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
{
response = await client.PostAsync(new Uri("http://apiendpoint"), content)
.AsTask(token);
}
token.ThrowIfCancellationRequested();
// Parse response and return result
}
catch (OperationCanceledException ocex)
{
return null;
}
}
剩下的只是调用 cts.Cancel()
方法并在处理程序中每次调用 GetMembers
之前创建一个新的 CancellationTokenSource
实例。当然,正如@Russell Hickey 提到的,cts
应该是全局的。 (如果这个 class 有多个实例并且你总是想在调用这个处理程序时取消 GetMembers
方法,甚至是静态的。通常我还有一个 class 来包装结果和有一个额外的 属性 IsSuccessful
来区分真正的 null
结果和失败的操作。
你已经差不多明白了。核心思想是单个CancellationTokenSource
只能取消一次,所以每次操作都要新建一个
private CancellationTokenSource cts;
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
// If there's a previous request, cancel it.
if (cts != null)
cts.Cancel();
// Create a CTS for this request.
cts = new CancellationTokenSource();
try
{
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
}
catch (OperationCanceledException)
{
// This happens if this operation was cancelled.
}
}