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 任务。

对我来说突出的一件事是使用 三个 独立的异步代码模式(AwaitContinueWithAsyncManager ) 而不是仅仅使用 Await.

另一件重要的事情是,您要返回一个 ActionResult - 表明这是一个 ASP.NET 应用程序 - 但谈论的是 "UI thread"。在 ASP.NET.

没有 UI 话题

因此,我将 "freezes the UI" 重新解释为 "does not return a result until the handler is complete",这正是 ASP.NET 应该 工作的方式。

所以,首先把不需要的AsyncManagerContinueWithTask.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 应用程序,您可以使用 AwaitHttpClient 来异步调用它。