UI 使用 Async-await 时冻结
UI freezes when using Async-await
我有这个函数可以冻结 UI:
Public Sub ValidateUrlContentAsync(externalApplyURL As String)
AsyncManager.OutstandingOperations.Increment()
Dim result = Threading.Tasks.Task.
Run( _
Async Function()
Return Await ValidateLinks.ValidateUrlContentAsync(externalApplyURL)
End Function).
ContinueWith(
Sub(t)
Try
If t.IsFaulted Then
Throw t.Exception
End If
If t.Result.Error IsNot Nothing Then
ErrorHandler.Log.Warn(
String.Format("ValidationError: {0}, Exception: {1}", externalApplyURL, t.Result.Error))
End If
AsyncManager.Parameters("validationResult") = t.Result.ResultValue.ToString()
Finally
AsyncManager.OutstandingOperations.Decrement()
End Try
End Sub)
End Sub
Public Function ValidateUrlContentCompleted(validationResult As String) As ActionResult
Return Json(validationResult, JsonRequestBehavior.AllowGet)
End Function
我认为 task.run
解决了这个问题,因为它创建了一个与 UI 线程分开的新线程,这段代码有什么问题?
您必须等待对 ValidateUrlContentAsnc 的调用。把它变成一个函数和 return 任务。
对我来说突出的一件事是使用 三个 独立的异步代码模式(Await
、ContinueWith
和 AsyncManager
) 而不是仅仅使用 Await
.
另一件重要的事情是,您要返回一个 ActionResult
- 表明这是一个 ASP.NET 应用程序 - 但谈论的是 "UI thread"。在 ASP.NET.
上 没有 UI 话题
因此,我将 "freezes the UI" 重新解释为 "does not return a result until the handler is complete",这正是 ASP.NET 应该 工作的方式。
所以,首先把不需要的AsyncManager
、ContinueWith
、Task.Run
代码全部去掉,真正简化了方法:
Public Function ValidateUrlContent(externalApplyURL As String) As Task(Of ActionResult)
Dim result = Await ValidateLinks.ValidateUrlContentAsync(externalApplyURL)
If result.Error IsNot Nothing Then
ErrorHandler.Log.Warn(String.Format("ValidationError: {0}, Exception: {1}", externalApplyURL, result.Error))
End If
Return Json(result.ResultValue.ToString(), JsonRequestBehavior.AllowGet)
End Function
接下来,解决"freezing the UI"问题。解决这个问题的正确位置是在UI,而不是在服务器端(ASP.NET)。防止UI冻结的方法是用异步方式调用服务器。如果您 UI 是一个 .NET 应用程序,您可以使用 Await
和 HttpClient
来异步调用它。
我有这个函数可以冻结 UI:
Public Sub ValidateUrlContentAsync(externalApplyURL As String)
AsyncManager.OutstandingOperations.Increment()
Dim result = Threading.Tasks.Task.
Run( _
Async Function()
Return Await ValidateLinks.ValidateUrlContentAsync(externalApplyURL)
End Function).
ContinueWith(
Sub(t)
Try
If t.IsFaulted Then
Throw t.Exception
End If
If t.Result.Error IsNot Nothing Then
ErrorHandler.Log.Warn(
String.Format("ValidationError: {0}, Exception: {1}", externalApplyURL, t.Result.Error))
End If
AsyncManager.Parameters("validationResult") = t.Result.ResultValue.ToString()
Finally
AsyncManager.OutstandingOperations.Decrement()
End Try
End Sub)
End Sub
Public Function ValidateUrlContentCompleted(validationResult As String) As ActionResult
Return Json(validationResult, JsonRequestBehavior.AllowGet)
End Function
我认为 task.run
解决了这个问题,因为它创建了一个与 UI 线程分开的新线程,这段代码有什么问题?
您必须等待对 ValidateUrlContentAsnc 的调用。把它变成一个函数和 return 任务。
对我来说突出的一件事是使用 三个 独立的异步代码模式(Await
、ContinueWith
和 AsyncManager
) 而不是仅仅使用 Await
.
另一件重要的事情是,您要返回一个 ActionResult
- 表明这是一个 ASP.NET 应用程序 - 但谈论的是 "UI thread"。在 ASP.NET.
因此,我将 "freezes the UI" 重新解释为 "does not return a result until the handler is complete",这正是 ASP.NET 应该 工作的方式。
所以,首先把不需要的AsyncManager
、ContinueWith
、Task.Run
代码全部去掉,真正简化了方法:
Public Function ValidateUrlContent(externalApplyURL As String) As Task(Of ActionResult)
Dim result = Await ValidateLinks.ValidateUrlContentAsync(externalApplyURL)
If result.Error IsNot Nothing Then
ErrorHandler.Log.Warn(String.Format("ValidationError: {0}, Exception: {1}", externalApplyURL, result.Error))
End If
Return Json(result.ResultValue.ToString(), JsonRequestBehavior.AllowGet)
End Function
接下来,解决"freezing the UI"问题。解决这个问题的正确位置是在UI,而不是在服务器端(ASP.NET)。防止UI冻结的方法是用异步方式调用服务器。如果您 UI 是一个 .NET 应用程序,您可以使用 Await
和 HttpClient
来异步调用它。