await (Referencia de C#)await (C# Reference)

El operador await se aplica a una tarea de un método asincrónico para insertar un punto de suspensión en la ejecución del método hasta que la tarea en espera se complete.The await operator is applied to a task in an asynchronous method to insert a suspension point in the execution of the method until the awaited task completes. La tarea representa el trabajo en curso.The task represents ongoing work.

await solo puede usarse en un método asincrónico que se ha modificado mediante la palabra clave async.await can only be used in an asynchronous method modified by the async keyword. Este tipo de método, que se define mediante el modificador async y que generalmente contiene una o más expresiones await, se denomina método asincrónico.Such a method, defined by using the async modifier and usually containing one or more await expressions, is referred to as an async method.

Nota

Las palabras clave async y await se han incluido en C# 5.The async and await keywords were introduced in C# 5. Para obtener una introducción a la programación asincrónica, vea Programación asincrónica con async y await.For an introduction to async programming, see Asynchronous Programming with async and await.

La tarea a la que se aplica el operador await se devuelve normalmente mediante una llamada a un método que implementa el patrón asincrónico basado en tareas.The task to which the await operator is applied typically is returned by a call to a method that implements the Task-Based Asynchronous Pattern. Incluyen métodos que devuelven objetos Task, Task<TResult>, ValueTask y ValueTask<TResult>.They include methods that return Task, Task<TResult>, ValueTask, and ValueTask<TResult> objects.

En el siguiente ejemplo, el método HttpClient.GetByteArrayAsync devuelve un Task<byte[]>.In the following example, the HttpClient.GetByteArrayAsync method returns a Task<byte[]>. La tarea garantiza que la matriz de bytes real se generará cuando finalice la tarea.The task is a promise to produce the actual byte array when the task is complete. El operador await suspende la ejecución hasta que el trabajo del método GetByteArrayAsync se completa.The await operator suspends execution until the work of the GetByteArrayAsync method is complete. Mientras tanto, el control vuelve al llamador de GetPageSizeAsync.In the meantime, control is returned to the caller of GetPageSizeAsync. Cuando la tarea finaliza la ejecución, la expresión await se evalúa como una matriz de bytes.When the task finishes execution, the await expression evaluates to a byte array.

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      string[] args = Environment.GetCommandLineArgs();
      if (args.Length > 1)
         GetPageSizeAsync(args[1]).Wait();
      else
         Console.WriteLine("Enter at least one URL on the command line.");
   }

   private static async Task GetPageSizeAsync(string url)  
   {  
       var client = new HttpClient();  
       var uri = new Uri(Uri.EscapeUriString(url));
       byte[] urlContents = await client.GetByteArrayAsync(uri);
       Console.WriteLine($"{url}: {urlContents.Length/2:N0} characters");  
   }  
}
// The following call from the command line:
//    await1 http://docs.microsoft.com
// displays output like the following: 
//   http://docs.microsoft.com: 7,967 characters


Importante

Para obtener el ejemplo completo, consulte Tutorial: Acceso a web usando Async y Await.For the complete example, see Walkthrough: Accessing the Web by Using Async and Await. Puede descargar el ejemplo desde Ejemplos de código para desarrolladores en el sitio web de Microsoft.You can download the sample from Developer Code Samples on the Microsoft website. El ejemplo está en el proyecto AsyncWalkthrough_HttpClient.The example is in the AsyncWalkthrough_HttpClient project.

Tal y como se muestra en el ejemplo anterior, si await se aplica al resultado de una llamada al método que devuelve Task<TResult>, el tipo de la expresión await es TResult.As shown in the previous example, if await is applied to the result of a method call that returns a Task<TResult>, then the type of the await expression is TResult. Si await se aplica al resultado de una llamada al método que devuelve Task, el tipo de la expresión await es void.If await is applied to the result of a method call that returns a Task, then the type of the await expression is void. En el siguiente ejemplo se ilustra la diferencia.The following example illustrates the difference.

// await keyword used with a method that returns a Task<TResult>.  
TResult result = await AsyncMethodThatReturnsTaskTResult();  
  
// await keyword used with a method that returns a Task.  
await AsyncMethodThatReturnsTask();  

// await keyword used with a method that returns a ValueTask<TResult>.
TResult result = await AsyncMethodThatReturnsValueTaskTResult();

Una expresión await no bloquea el subproceso en el que se ejecuta.An await expression does not block the thread on which it is executing. En su lugar, hace que el compilador suscriba el resto del método asincrónico como una continuación de la tarea esperada.Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. A continuación, el control vuelve al llamador del método asincrónico.Control then returns to the caller of the async method. Cuando la tarea se completa, invoca su continuación y la ejecución del método asincrónico se reanuda donde se quedó.When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.

Una expresión await solo puede aparecer en el cuerpo de su método envolvente, en una expresión lambda o en un método anónimo que debe marcarse con un modificador async.An await expression can occur only in the body of its enclosing method, lambda expression, or anonymous method, which must be marked with an async modifier. El término await solo sirve como palabra clave en ese contexto.The term await serves as a keyword only in that context. En cualquier otra parte, se interpretará como identificador.Elsewhere, it is interpreted as an identifier. Dentro del método, expresión lambda o método anónimo, una expresión await no se puede producir en el cuerpo de una función sincrónica, en una expresión de consulta, en el bloque de una instrucción lock, ni en un contexto unsafe.Within the method, lambda expression, or anonymous method, an await expression cannot occur in the body of a synchronous function, in a query expression, in the block of a lock statement, or in an unsafe context.

ExcepcionesExceptions

La mayoría de los métodos asincrónicos devuelven un objeto Task o Task<TResult>.Most async methods return a Task or Task<TResult>. Las propiedades de la tarea devuelta llevan información acerca de su estado e historial, por ejemplo, si la tarea se ha completado, si el método asincrónico produjo una excepción o si se ha cancelado y cuál es el resultado final.The properties of the returned task carry information about its status and history, such as whether the task is complete, whether the async method caused an exception or was canceled, and what the final result is. El operador await tiene acceso a esas propiedades llamando a métodos en el objeto devuelto mediante el método GetAwaiter.The await operator accesses those properties by calling methods on the object returned by the GetAwaiter method.

Si espera un método asincrónico que devuelve una tarea y causa una excepción, el operador await volverá a generar la excepción.If you await a task-returning async method that causes an exception, the await operator rethrows the exception.

Si espera un método asincrónico que devuelve una tarea y se cancela, el operador await volverá a generar OperationCanceledException.If you await a task-returning async method that's canceled, the await operator rethrows an OperationCanceledException.

Una única tarea en estado de error puede reflejar varias excepciones.A single task that is in a faulted state can reflect multiple exceptions. Por ejemplo, la tarea podría ser el resultado de una llamada a Task.WhenAll.For example, the task might be the result of a call to Task.WhenAll. Cuando espera dicha tarea, la operación await vuelve a generar únicamente una de las excepciones.When you await such a task, the await operation rethrows only one of the exceptions. Sin embargo, no se puede predecir cuál de las excepciones se vuelve a generar.However, you can't predict which of the exceptions is rethrown.

Para obtener ejemplos de control de errores en métodos asincrónicos, vea try-catch.For examples of error handling in async methods, see try-catch.

EjemploExample

En el ejemplo siguiente se devuelve el número total de caracteres en las páginas cuyas direcciones URL se pasan como argumentos de línea de comandos.The following example returns the total number of characters in the pages whose URLs are passed to it as command line arguments. En el ejemplo se llama al método GetPageLengthsAsync, que se marca con la palabra clave async.The example calls the GetPageLengthsAsync method, which is marked with the async keyword. El método GetPageLengthsAsync a su vez usa la palabra clave await para esperar llamadas del método HttpClient.GetStringAsync.The GetPageLengthsAsync method in turn uses the await keyword to await calls to the HttpClient.GetStringAsync method.

using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

class Example
{
   static async Task Main()
   {
      string[] args = Environment.GetCommandLineArgs();
      if (args.Length < 2)
         throw new ArgumentNullException("No URIs specified on the command line.");

      // Don't pass the executable file name
      var uris = args.Skip(1).ToArray();

      long characters = await GetPageLengthsAsync(uris);
      Console.WriteLine($"{uris.Length} pages, {characters:N0} characters");
   }

   private static async Task<long> GetPageLengthsAsync(string[] uris)
   {
      var client = new HttpClient();
      long pageLengths = 0;

      foreach (var uri in uris)
      {
         var escapedUri = new Uri(Uri.EscapeUriString(uri));
         string pageContents = await client.GetStringAsync(escapedUri);
         Interlocked.Add(ref pageLengths, pageContents.Length);
      }
      
      return pageLengths;
   }
}

El ejemplo anterior utiliza C# 7.1, que admite el método async Main.The preceding example uses C# 7.1, which supports the async Main method. Dado que las versiones anteriores de C# no admiten los puntos de entrada de aplicación que devuelven Task o Task<TResult>, no se puede aplicar el modificador async al método Main y esperar la llamada al método GetPageLengthsAsync.Because earlier C# versions don't support application entry points that return Task or Task<TResult>, you cannot apply the async modifier to the Main method and await the GetPageLengthsAsync method call. En ese caso, podemos garantizar que el método Main espera a que se complete la operación asincrónica recuperando el valor de la propiedad Task<TResult>.Result.In that case, you can ensure that the Main method waits for the async operation to complete by retrieving the value of the Task<TResult>.Result property. Para las tareas que no devuelven un valor, puede llamar al método Task.Wait.For tasks that do not return a value, you can call the Task.Wait method. Para información sobre cómo seleccionar la versión de idioma, consulte Seleccionar la versión del lenguaje C#.For information about how to select the language version, see Select the C# language version.

Vea tambiénSee also