En programación informática , el patrón async/await es una característica sintáctica de muchos lenguajes de programación que permite estructurar una función asíncrona y no bloqueante de forma similar a una función síncrona ordinaria.
Está semánticamente relacionado con el concepto de corrutina y a menudo se implementa utilizando técnicas similares, y su propósito principal es brindar oportunidades para que el programa ejecute otro código mientras espera a que se complete una tarea asíncrona de larga duración, generalmente representada por promesas o estructuras de datos similares . Esta característica se encuentra en C# , [ 1 ] : 10 C++ , Python , F# , Hack , Julia , Dart , Kotlin , Rust , [ 2 ] Nim , [ 3 ] JavaScript y Swift . [ 4 ]
Historia
F# añadió flujos de trabajo asíncronos con puntos await en la versión 2.0 en 2007. [ 5 ] Esto influyó en el mecanismo async/await añadido a C#. [ 6 ]
El desarrollador principal de Haskell, Simon Marlow, creó el paquete async en 2010. [ 7 ]
Microsoft lanzó por primera vez una versión de C# con async/await en Async CTP (2011). Posteriormente se lanzó oficialmente en C# 5 (2012). [ 8 ] [ 1 ] : 10
Python agregó soporte para async/await con la versión 3.5 en 2015 [ 9 ] agregando 2 nuevas palabras clave , asyncy await.
TypeScript añadió soporte para async/await con la versión 1.7 en 2015. [ 10 ]
JavaScript añadió soporte para async/await en 2017 como parte de la edición ECMAScript 2017 de JavaScript.
Rust añadió soporte para async/await con la versión 1.39.0 en 2019 utilizando la asyncpalabra clave y el operador posfijo, ambos introducidos en la edición de 2018 del lenguaje. [ 11 ].await
C++ agregó soporte para async/await con la versión 20 en 2020 con 3 nuevas palabras clave co_return, co_await, co_yield.
Swift añadió soporte para async/await con la versión 5.5 en 2021, añadiendo 2 nuevas palabras clave asyncy await. Esto se lanzó junto con una implementación concreta del modelo Actor con la actorpalabra clave [ 12 ] que utiliza async/await para mediar el acceso a cada actor desde fuera.
Ejemplo
La siguiente función de C# , que descarga un recurso desde una URI y devuelve la longitud del recurso, utiliza este patrón async/await:
using System ; using System.Net.Http ; using System.Threading.Tasks ;public async Task < int > FindSizeOfPageAsync ( Uri uri ) { HttpClient client = new (); byte [] data = await client . GetByteArrayAsync ( uri ); return data . Length ; }- En primer lugar, la
asyncpalabra clave indica a C# que el método es asíncrono, lo que significa que puede usar un número arbitrario deawaitexpresiones y vinculará el resultado a una promesa . [ 1 ] : 165–168 - El tipo de retorno ,
System.Threading.Tasks.Task<T>, es el análogo de C# al concepto de promesa, y aquí se indica que tiene un valor de resultado de tipoint. (Tenga en cuenta que al devolver unvoid, laSystem.Threading.Tasks.Taskclase no tiene parámetros de tipo . - La primera expresión que se ejecutará cuando se llame a este método será , [ 13 ] : 189–190, 344 [ 1 ] : 882 que es otro método asíncrono que devuelve un . Debido a que este método es asíncrono, no descargará todo el lote de datos antes de devolverlo. En cambio, comenzará el proceso de descarga utilizando un mecanismo no bloqueante (como un hilo en segundo plano ) e inmediatamente devolverá un no resuelto, no rechazado a esta función.
newHttpClient().GetByteArrayAsync(uri)Task<byte[]>Task<byte[]> - Con la
awaitpalabra clave adjunta a laTask, esta función procederá inmediatamente a devolver un a su llamador, quien luego podrá continuar con otro procesamiento según sea necesario.Task<int> - Una vez
GetByteArrayAsync()que finalice su descarga, resolverá elTaskque devolvió con los datos descargados. Esto activará una devolución de llamada y haráFindPageSizeAsync()que continúe la ejecución asignando ese valor adata. - Finalmente, el método devuelve un entero
data.Lengthsimple que indica la longitud del array. El compilador reinterpreta esto como la resolución del array que devolvió anteriormente, lo que activa una función de devolución de llamada en la función que llama al método para procesar ese valor de longitud.Task
Una función que utiliza async/await puede usar tantas awaitexpresiones como quiera, y cada una se manejará de la misma manera (aunque una promesa solo se devolverá al llamador para el primer await, mientras que todos los demás await utilizarán devoluciones de llamada internas). Una función también puede contener un objeto promesa directamente y realizar otro procesamiento primero (incluido el inicio de otras tareas asíncronas), retrasando la espera de la promesa hasta que se necesite su resultado. Las funciones con promesas también tienen métodos de agregación de promesas que permiten al programa esperar varias promesas a la vez o en algún patrón especial (como el de C# Task.WhenAll(), [ 1 ] : 174–175 [ 13 ] : 664–665 que devuelve un valor sin valor Taskque se resuelve cuando todas las tareas en los argumentos se han resuelto). Muchos tipos de promesas también tienen características adicionales más allá de lo que normalmente usa el patrón async/await, como poder configurar más de una devolución de llamada de resultado o inspeccionar el progreso de una tarea de ejecución especialmente larga.
En el caso particular de C#, y en muchos otros lenguajes con esta característica, el patrón async/await no es una parte fundamental del entorno de ejecución del lenguaje, sino que se implementa mediante expresiones lambda o continuaciones en tiempo de compilación. Por ejemplo, el compilador de C# probablemente traduciría el código anterior a algo como lo siguiente antes de convertirlo a su formato de bytecode IL :
using System ; using System.Net.Http ; using System.Threading.Tasks ;public Task < int > FindSizeOfPageAsync ( Uri uri ) { HttpClient client = new (); Task < byte [] > dataTask = client . GetByteArrayAsync ( uri ); Task < int > afterDataTask = dataTask . ContinueWith (( originalTask ) => { return originalTask . Result . Length ; }); return afterDataTask ; }Debido a esto, si un método de interfaz necesita devolver un objeto Promise, pero en sí mismo no requiere awaiten el cuerpo esperar en ninguna tarea asíncrona, tampoco necesita el asyncmodificador y en su lugar puede devolver un objeto Promise directamente. Por ejemplo, una función podría proporcionar una Promise que se resuelva inmediatamente a algún valor de resultado (como en C# Task.FromResult()[ 13 ] : 656 ), o puede simplemente devolver la Promise de otro método que resulta ser la Promise exacta que se necesita (como cuando se delega a una sobrecarga ).
Sin embargo, una advertencia importante de esta funcionalidad es que, si bien el código se asemeja al código de bloqueo tradicional, en realidad no es de bloqueo y es potencialmente multihilo, lo que significa que pueden ocurrir muchos eventos intermedios mientras se espera a que awaitse resuelva la promesa a la que apunta. Por ejemplo, el siguiente código, aunque siempre tiene éxito en un modelo de bloqueo sin await, puede experimentar eventos intermedios durante awaity, por lo tanto, puede encontrar que el estado compartido cambia sin previo aviso:
using System ; using System.Diagnostics ; using System.Net.Http ;string nombre = estado.nombre ; HttpClient cliente = nuevo ( ) ; byte [ ] datos = await cliente.GetByteArrayAsync ( uri ) ;// Posible fallo, ya que el valor de state.a puede haber sido modificado // por el controlador de un evento potencialmente interviniente . Debug.Assert ( name == state.name ) ;devolver datos.Longitud ;Implementaciones
do
El lenguaje C no admite await/async. Algunas bibliotecas de corrutinas como s_task [ 14 ] simulan las palabras clave await/async con macros.
#include <stdio.h> #include "s_task.h"constexpr int STACK_SIZE = 64 * 1024 / sizeof ( int );// define la memoria de pila para las tareas int g_stack_main [ STACK_SIZE ]; int g_stack0 [ STACK_SIZE ]; int g_stack1 [ STACK_SIZE ];void sub_task ( __async__ , void * arg ) { int n = ( int )( size_t ) arg ; for ( int i = 0 ; i < 5 ; ++ i ) { printf ( "tarea %d, retraso segundos = %d, i = %d \n " , n , n , i ); s_task_msleep ( __await__ , n * 1000 ); // s_task_yield(__await__); } }void main_task ( __async__ , void * arg ) { // crear dos subtareas s_task_create ( g_stack0 , sizeof ( g_stack0 ), sub_task , ( void * ) 1 ); s_task_create ( g_stack1 , sizeof ( g_stack1 ), sub_task , ( void * ) 2 );for ( int i = 0 ; i < 4 ; ++ i ) { printf ( "task_main arg = %p, i = %d \n " , arg , i ); s_task_yield ( __await__ ); }// esperar a que las subtareas finalicen s_task_join ( __await__ , g_stack0 ); s_task_join ( __await__ , g_stack1 ); }int main ( int argc , char * argv []) { s_task_init_system ();// crea la tarea principal s_task_create ( g_stack_main , sizeof ( g_stack_main ), main_task , ( void * )( size_t ) argc ); s_task_join ( __await__ , g_stack_main ); printf ( "todas las tareas han terminado \n " ); return 0 ; }C++
En C++, `await` (llamado así co_awaitpara enfatizar su contexto en corrutinas) se ha fusionado oficialmente en C++20 . [ 15 ] El soporte para `await`, las corrutinas y las palabras clave como `await` co_awaitestán disponibles en los compiladores GCC y MSVC, mientras que Clang tiene soporte parcial. Una clase de tarea propia, `await` std::execution::task<T, Env>, se introdujo en C++26 . [ 16 ] Para llamarla, use `await` std::execution::sync_wait(), que devuelve `await` std::optional<std::tuple<Ts...>>. [ 17 ]
Cabe destacar que std::promisey std::future, aunque parecería que serían objetos awaitable, no implementan ninguno de los mecanismos necesarios para ser devueltos por corrutinas y ser esperados mediante co_await. Los programadores deben implementar varias funciones miembro públicas, como await_ready, await_suspend, y await_resumeen el tipo de retorno para que el tipo pueda ser esperado. Los detalles se pueden encontrar en cppreference. [ 18 ]
importar std ;using std :: optional ; using std :: tuple ; using std :: execution :: task ;tarea < int > agregar ( int a , int b ) noexcept { co_return a + b ; }tarea < int > prueba () { int ret = co_await add ( 1 , 2 ); std :: println ( "Return {}" , ret ); co_return ret ; }int main ( int argc , char * argv []) { optional < tuple < int >> result = std :: execution :: sync_wait ( test ()); std :: println ( "Resultado: {}" , std :: get < 0 > ( result ). value_or ( std :: make_tuple ( -1 )));devolver 0 ; }DO#
En 2012, C# agregó el patrón async/await en C# con la versión 5.0, al que Microsoft se refiere como el patrón asíncrono basado en tareas (TAP). [ 19 ] Los métodos asíncronos generalmente devuelven void, Task, , [ 13 ] : 35 [ 20 ] : 546–547 [ 1 ] : 22, 182 o . [ 13 ] : 651–652 [ 1 ] : 182–184 El código del usuario puede definir tipos personalizados que los métodos asíncronos pueden devolver a través de constructores de métodos asíncronos personalizados , pero este es un escenario avanzado y poco común. [ 21 ] Los métodos asíncronos que devuelven están destinados a los manejadores de eventos ; en la mayoría de los casos donde un método síncrono devolvería , se recomienda devolver en su lugar, ya que permite un manejo de excepciones más intuitivo (tenga en cuenta que no es válido en C#). [ 22 ]Task<T>ValueTaskValueTask<T>voidvoidTaskTask<void>
Los métodos que utilizan awaitdeben declararse con la asyncpalabra clave. En los métodos que tienen un valor de retorno de tipo Task<T>, los métodos declarados con asyncdeben tener una instrucción de retorno de tipo asignable a Ten lugar de Task<T>; el compilador envuelve el valor en el Task<T>genérico. También es posible usar awaitmétodos que tienen un tipo de retorno de Tasko que se declaran sin .Task<T>async
El siguiente método asíncrono descarga datos de una URL await. Debido a que este método emite una tarea para cada URI antes de requerir su finalización con la awaitpalabra clave, los recursos pueden cargarse al mismo tiempo en lugar de esperar a que el último recurso termine antes de comenzar a cargar el siguiente.
espacio de nombres Wikipedia.Ejemplos ;using System ; using System.Collections.Generic ; using System.Net.Http ; using System.Threading.Tasks ;public class Example { public async Task < int > SumPageSizesAsync ( IEnumerable < Uri > uris ) { HttpClient client = new (); int total = 0 ; List < Task < byte [] >> loadUriTasks = new ();foreach ( Uri uri in uris ) { byte [] loadUriTask = client . GetByteArrayAsync ( uri ); loadUriTasks . Add ( loadUriTask ); }foreach ( Task < byte [] >> loadUriTask in loadUriTasks ) { statusText . Text = $"Se encontraron {total} bytes..." ; byte [] resourceAsBytes = await loadUriTask ; total += resourceAsBytes . Length ; }statusText . Texto = $"Encontrados {total} bytes en total" ;devolver total ; }static async Task Main ( string [] args ) { List < Uri > uris = new { new Uri ( "https://en.wikipedia.org" ), new Uri ( "https://www.microsoft.com" ), new Uri ( "https://www.github.com" ) }int totalBytes = await SumPageSizesAsync ( uris ); Console . WriteLine ( $"Total bytes descargados: {totalbytes}" ); } }F#
En 2007, F# incorporó flujos de trabajo asíncronos con la versión 2.0. [ 23 ] Los flujos de trabajo asíncronos se implementan como CE ( expresiones de cálculo ). Se pueden definir sin especificar ningún contexto especial (como asyncen C#). Los flujos de trabajo asíncronos de F# añaden un signo de exclamación (!) a las palabras clave para iniciar tareas asíncronas.
La siguiente función asíncrona descarga datos desde una URL utilizando un flujo de trabajo asíncrono:
let asyncSumPageSizes ( uris : # seq < Uri >) : Async < int > = async { use httpClient = new HttpClient () let! pages = uris |> Seq . map ( httpClient . GetStringAsync >> Async . AwaitTask ) |> Async . Parallel return pages |> Seq . fold ( fun accumulator current -> current . Length + accumulator ) 0 }Java
Java no tiene palabras clave ` asyncand` awaiten el lenguaje, sin embargo, se puede emular usando el java.util.concurrentpaquete, como la clase java.util.concurrent.CompletableFuture<T>(introducida en Java 8). La programación asíncrona se mejoró posteriormente en Java 21 con la introducción de hilos virtuales y ámbitos de tareas estructurados.
paquete org.wikipedia.examples ;import java.util.concurrent.CompletableFuture ; import java.util.concurrent.ExecutionException ; import java.util.concurrent.ExecutorService ; import java.util.concurrent.Executors ; import java.util.concurrent.Future ; import java.util.concurrent.StructuredTaskScope ;public class AsyncExample { public String fetchData () { // Simula una operación que consume mucho tiempo (por ejemplo, solicitud de red, consulta de base de datos) try { Thread . sleep ( 2000 ); } catch ( InterruptedException e ) { Thread . currentThread (). interrupt (); } return "Datos de una fuente remota" ; }public CompletableFuture < String > fetchDataAsync () { return CompletableFuture . supplyAsync (() -> fetchData ()); }public static void main ( String [] args ) throws ExecutionException , InterruptedException { AsyncExample example = new AsyncExample ();// Usando CompletableFuture (Java 8) System . out . println ( "Iniciando operación asíncrona..." );CompletableFuture < String > future = example . fetchDataAsync ();System.out.println ( " Realizando otro trabajo ... " ) ;// Esperar el resultado (similar a 'await') String result = future . get (); System . out . printf ( "Resultado recibido: %s%n" , result );// Uso de hilos virtuales (Java 21): ExecutorService extor = Executors . newVirtualThreadPerTaskExecutor (); System . out . println ( "Iniciando operación de hilo virtual..." );Futuro < Cadena > fut = extor . enviar (() -> { devolver ejemplo . fetchData (); });System.out.println ( " Realizando otro trabajo ... " ) ;String resultado = future.get ( ); System.out.printf ( " Resultado recibido: %s % n " , resultado ) ; extor.shutdown ( ) ;// Usando StructuredTaskScope (Java 21) try ( StructuredTaskScope . ShutdownOnFailure scope = new StructuredTaskScope . ShutdownOnFailure ()) { StructuredTaskScope . Subtask < String > dataTask = scope . fork ( example :: fetchData ); System . out . println ( "Realizando otro trabajo..." );ámbito.join (); // esperar a que finalicen todas las tareas ámbito.throwIfFailed ( ) ; // propagar si hay excepcionesString resultado = futuro.get ( ); System.out.printf ( " Resultado recibido: %s% n " , resultado ) ; } } }JavaScript
El operador `await` en JavaScript (y TypeScript) solo se puede usar dentro de una función asíncrona o en el nivel superior de un módulo . Si el parámetro es una promesa , la ejecución de la función asíncrona se reanudará cuando la promesa se resuelva (a menos que la promesa sea rechazada, en cuyo caso se lanzará un error que se puede manejar con el manejo de excepciones normal de JavaScript ). Si el parámetro no es una promesa, el parámetro en sí se devolverá inmediatamente. [ 24 ]
Muchas bibliotecas proporcionan objetos Promise que también se pueden usar con await, siempre que cumplan con la especificación para promesas nativas de JavaScript. Sin embargo, las promesas de la biblioteca jQuery no eran compatibles con Promises/A+ hasta jQuery 3.0. [ 25 ]
A continuación se muestra un ejemplo (modificado a partir de este artículo [ 26 ] ):
interfaz DBResponse { id : string ; rev? : string ; ok? : boolean ; }Interfaz Documento { _id : cadena ; _rev? : cadena ; [ clave : cadena ] : cualquiera ; }interface Database { post ( doc : object ) : Promise < DBResponse > ; get ( id : string ) : Promise < Document > ; }declarar constante db : Base de datos ;función asíncrona createNewDoc ( ) : Promise <Document> { const response : DBResponse = await db.post ( { } ) ; const doc : Document = await db.get ( response.id ) ; return doc ; }función asíncrona principal () : Promise < void > { try { const doc : Document = await createNewDoc (); console . log ( doc ); } catch ( err : Error ) { console . error ( "Error al crear o obtener el documento:" , err ); } }principal ();Node.js versión 8 incluye una utilidad que permite usar los métodos basados en devoluciones de llamada de la biblioteca estándar como promesas. [ 27 ]
Perl
El módulo Future::AsyncAwait [ 28 ] fue objeto de una subvención de la Fundación Perl en septiembre de 2018. [ 29 ]
Pitón
Python 3.5 (2015) [ 30 ] ha añadido soporte para async/await como se describe en PEP 492 (escrito e implementado por Yury Selivanov ). [ 31 ]
import asyncioasync def main () -> None : print ( "hola" ) await asyncio . sleep ( 1 ) print ( "mundo" )if __name__ == "__main__" : asyncio . run ( main ())Óxido
El 7 de noviembre de 2019, se lanzó async/await en la versión estable de Rust. [ 32 ] Las funciones asíncronas en Rust se desazucaran a funciones simples que devuelven valores que implementan el rasgo Future. Actualmente se implementan con una máquina de estados finitos . [ 33 ]
// En el archivo Cargo.toml del crate, necesitamos `futures = "0.3.0"` en la sección de dependencias, // para poder usar el crate futuresextern crate futures ; // Actualmente no hay ningún ejecutor en la biblioteca `std`.usar std :: future :: Future ;// Esto se desdulza a algo como // `fn async_add_one(num: u32) -> impl Future<Output = u32>` async fn async_add_one ( num : u32 ) -> u32 { num + 1 }async fn example_task () -> impl Future < Output = () > { let number = async_add_one ( 5 ). await ; println! ( "5 + 1 = {}" , number ); }fn main () { // Crear el Future no inicia la ejecución. let future = example_task ();// El `Future` solo se ejecuta cuando lo consultamos, a diferencia de JavaScript. futures :: executor :: block_on ( future ); }Rápido
Swift 5.5 (2021) [ 34 ] agregó soporte para async/await como se describe en SE-0296. [ 35 ]
func getNumber ( ) async throws - > Int { try await Task.sleep ( nanoseconds : 1_000_000_000 ) return 42 }Tarea { let first = try await getNumber () let second = try await getNumber () print ( first + second ) }Beneficios y críticas
El patrón async/await es especialmente atractivo para los diseñadores de lenguajes que no tienen ni controlan su propio entorno de ejecución , ya que async/await puede implementarse únicamente como una transformación a una máquina de estados en el compilador. [ 36 ]
Los defensores afirman que con async/await se puede escribir código asíncrono y no bloqueante que se asemeja mucho al código síncrono y bloqueante tradicional. En particular, se ha argumentado que await es la mejor manera de escribir código asíncrono en programas de paso de mensajes ; entre sus ventajas se destacan su similitud con el código bloqueante, su legibilidad y la mínima cantidad de código repetitivo . [ 37 ]
Los críticos de async/await señalan que este patrón tiende a provocar que el código circundante también sea asíncrono; y que su naturaleza contagiosa divide los ecosistemas de bibliotecas de los lenguajes entre bibliotecas y API síncronas y asíncronas, un problema que a menudo se denomina "coloración de funciones". [ 38 ] Las alternativas a async/await que no sufren este problema se denominan "sin color". Ejemplos de diseños sin color incluyen las goroutines de Go y los hilos virtuales de Java . [ 39 ]
Véase también
Referencias
- 1 2 3 4 5 6 7 Skeet, Jon (23 de marzo de 2019). C# en profundidad . Manning. ISBN 978-1617294532.
- ↑ "Anuncio de Rust 1.39.0" . Consultado el 7 de noviembre de 2019 .
- ↑ "std/async" . Archivado del original el 29 de septiembre de 2025. Consultado el 19 de enero de 2020 .
- ↑ "Concurrencia: El lenguaje de programación Swift (Swift 5.5)" . docs.swift.org . Consultado el 28 de septiembre de 2021 .
- ↑ Syme, Don; Petricek, Tomas; Lomov, Dmitry (2011). "El modelo de programación asíncrona de F#" . Aspectos prácticos de los lenguajes declarativos . Lecture Notes in Computer Science. Vol. 6539. Springer Link. pp. 175–189 . doi : 10.1007/978-3-642-18378-2_15 . ISBN 978-3-642-18377-5. Consultado el 29 de abril de 2021 .
- ↑ "La historia temprana de F#, HOPL IV" . Biblioteca digital de ACM . Consultado el 29 de abril de 2021 .
- ↑ "async: Ejecuta operaciones de E/S de forma asíncrona y espera sus resultados" . Hackage .
- ↑ Hejlsberg, Anders. "Anders Hejlsberg: Introducción a la programación asíncrona: simplificando la programación asíncrona" . Canal 9 MSDN . Microsoft . Consultado el 5 de enero de 2021 .
- ↑ "Novedades de Python 3.5 — Documentación de Python 3.9.1" . docs.python.org . Consultado el 5 de enero de 2021 .
- ↑ Gaurav, Seth (30 de noviembre de 2015). "Anuncio de TypeScript 1.7" . TypeScript . Microsoft . Consultado el 5 de enero de 2021 .
- ↑ Matsakis, Niko. "¡Async-await en Rust estable! | Blog de Rust" . blog.rust-lang.org . Blog de Rust . Consultado el 5 de enero de 2021 .
- ↑ "Concurrencia: el lenguaje de programación Swift (Swift 5.6)" .
- ^ Albahari , José (2022 ) . C# 10 en pocas palabras . O'Reilly. ISBN 978-1-098-12195-2.
- ↑ "s_task - biblioteca de corrutinas awaitable para C" . GitHub .
- ↑ "El Comité ISO C++ anuncia que el diseño de C++20 ya está completo en cuanto a funcionalidades" . 25 de febrero de 2019.
- ↑ Dietmar Kühl, Maikel Nadolski (18 de mayo de 2025). "Agregar un tipo de tarea de corrutina" (PDF) . open-std.org . WG21.
- ↑ cppreference.com. "std::execution::sync_wait" . cppreference.com . cppreference.com . Consultado el 15 de febrero de 2026 .
- ↑ "Corrutinas (C++20)" .
- ↑ "Patrón asíncrono basado en tareas" . Microsoft . Consultado el 28 de septiembre de 2020 .
- ↑ Price, Mark J. (2022). C# 8.0 y .NET Core 3.0: Desarrollo multiplataforma moderno: Cree aplicaciones con C#, .NET Core, Entity Framework Core, ASP.NET Core y ML.NET usando Visual Studio Code . Packt. ISBN 978-1-098-12195-2.
- ↑ Tepliakov, Sergey (11 de enero de 2018). "Extendiendo los métodos asíncronos en C#" . Soporte para desarrolladores . Recuperado el 30 de octubre de 2022 .
- ↑ Stephen Cleary, Async/Await: Mejores prácticas en programación asíncrona
- ↑ "Introducción a los flujos de trabajo asíncronos de F#" . 10 de octubre de 2007.
- ↑ "await - JavaScript (MDN)" . Consultado el 2 de mayo de 2017 .
- ↑ "Guía de actualización de jQuery Core 3.0" . Consultado el 2 de mayo de 2017 .
- ↑ "Domando a la bestia asíncrona con ES7" . Consultado el 12 de noviembre de 2015 .
- ↑ Fundación, Node.js (30 de mayo de 2017). " Node v8.0.0 (actual) - Node.js" . Node.js.
- ↑ "Future::AsyncAwait - sintaxis de subrutina diferida para futuros" .
- ↑ "Votaciones de subvenciones de septiembre de 2018 - The Perl Foundation" . news.perlfoundation.org . Consultado el 26 de marzo de 2019 .
- ↑ "Python Release Python 3.5.0" .
- ↑ "PEP 492 – Corrutinas con sintaxis async y await" .
- ↑ Matsakis, Niko. "¡Async-await en Rust estable!" . Blog de Rust . Consultado el 7 de noviembre de 2019 .
- ↑ Oppermann, Philipp. "Async/Await" . Consultado el 28 de octubre de 2020 .
- ↑ "Copia archivada" . Archivado del original el 23/01/2022 . Consultado el 20/12/2021 .
{{cite web}}: CS1 mantenimiento: copia archivada como título ( enlace ) - ↑ "SE-0296" . GitHub .
- ↑ "Parte 3 de Async: cómo el compilador de C# implementa las funciones asíncronas" .
- ↑ 'Sin errores' Hare. Ocho maneras de manejar retornos no bloqueantes en programas de paso de mensajes CPPCON, 2018
- ↑ "¿De qué color es tu función?" .
- ↑ "Hilos virtuales" .
- Flujo de control