Await 运算符 (Visual Basic)

在异步方法或 Lambda 表达式中对操作数应用 Await 运算符可暂停执行方法,直到所等待的任务完成。 任务表示正在进行的工作。

使用 Await 的方法必须具有 Async 修饰符。 使用 Async 修饰符定义并且通常包含一个或多个 Await 表达式的这类方法称为异步方法。

注意

AsyncAwait 关键字是在 Visual Studio 2012 中引入的。 有关异步编程的说明,请参阅使用 Async 和 Await 的异步编程

通常,应用 Await 运算符的任务通常是方法调用的返回值,这种方法实现基于任务的异步模式,即 TaskTask<TResult>

在以下代码中,HttpClient 方法 GetByteArrayAsync 返回 getContentsTask,一个 Task(Of Byte())。 当操作完成时,任务约定生成一个实际字节数组。 Await 运算符应用于 getContentsTask 以在 SumPageSizesAsync 中挂起执行,直到 getContentsTask 完成。 同时,控制权会返回给 SumPageSizesAsync 的调用方。 当 getContentsTask 完成之后,Await 表达式计算为字节数组。

Private Async Function SumPageSizesAsync() As Task

    ' To use the HttpClient type in desktop apps, you must include a using directive and add a
    ' reference for the System.Net.Http namespace.
    Dim client As HttpClient = New HttpClient()
    ' . . .
    Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url)
    Dim urlContents As Byte() = Await getContentsTask

    ' Equivalently, now that you see how it works, you can write the same thing in a single line.
    'Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    ' . . .
End Function

重要

有关完整示例,请参阅演练:使用 async 和 await 访问 Web。 可以从 .NET 示例浏览器下载该示例。 示例代码位于 SerialAsyncExample 项目中。

如果 Await 应用于返回 Task(Of TResult) 的方法调用结果,则 Await 表达式的类型为 TResult。 如果 Await 应用于返回 Task 的方法调用结果,则 Await 表达式不返回值。 以下示例演示了差异。

' Await used with a method that returns a Task(Of TResult).
Dim result As TResult = Await AsyncMethodThatReturnsTaskTResult()

' Await used with a method that returns a Task.
Await AsyncMethodThatReturnsTask()

Await 表达式或声明不阻止正在执行它的线程。 而是导致编译器在 Await 表达式之后,将剩下的异步方法注册为等待任务的后续部分。 控制权随后会返回给异步方法的调用方。 任务完成时,它会调用其延续任务,异步方法的执行会在暂停的位置处恢复。

Await 表达式只出现在由 Async 修饰符标记的一个立即封闭方法体或 lambda 表达式中。 术语 Await 在该上下文中仅用作关键字。 在其他位置,它会解释为标识符。 在 Async 方法或 lambda 表达式中,Await 表达式不能出现在查询表达式中、Try…Catch...Finally 语句CatchFinally 块中、ForFor Each 循环的循环控制变量表达式中或者 SyncLock 语句的主体中。

例外

大多数异步方法返回 TaskTask<TResult>。 返回任务的属性携带有关其状态和历史记录的信息,如任务是否完成、异步方法是否导致异常或已取消以及最终结果是什么。 Await 运算符可访问这些属性。

如果等待的返回任务的异步方法会导致异常,则 Await 运算符重新引发异常。

如果等待的返回任务的异步方法取消,Await 运算符将重新引发 OperationCanceledException

处于故障状态的单个任务可以反映多个异常。 例如,任务可能是对 Task.WhenAll 调用的结果。 等待此类任务时,等待操作仅重新引发异常之一。 但是,无法预测重新引发的异常。

有关异步方法中的错误处理的示例,请参阅 Try...Catch...Finally 语句

示例

下面的 Windows 窗体示例阐释如何在异步方法 WaitAsynchronouslyAsync 中使用 Await。 将该方法的行为与 WaitSynchronously 的行为进行对比。 如果没有应用 Await 运算符,WaitSynchronously 就会同步运行,而不管其定义中是否使用了 Async 修饰符和在主体中是否调用了 Thread.Sleep

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ' Call the method that runs asynchronously.
    Dim result As String = Await WaitAsynchronouslyAsync()

    ' Call the method that runs synchronously.
    'Dim result As String = Await WaitSynchronously()

    ' Display the result.
    TextBox1.Text &= result
End Sub

' The following method runs asynchronously. The UI thread is not
' blocked during the delay. You can move or resize the Form1 window
' while Task.Delay is running.
Public Async Function WaitAsynchronouslyAsync() As Task(Of String)
    Await Task.Delay(10000)
    Return "Finished"
End Function

' The following method runs synchronously, despite the use of Async.
' You cannot move or resize the Form1 window while Thread.Sleep
' is running because the UI thread is blocked.
Public Async Function WaitSynchronously() As Task(Of String)
    ' Import System.Threading for the Sleep method.
    Thread.Sleep(10000)
    Return "Finished"
End Function

另请参阅