El futuro: async transparente en Solid 2.0
Qué significa que Solid 2.0 lleve lo asíncrono al núcleo del sistema reactivo: derivaciones que pueden ser async, un estado pendiente que se propaga por el grafo como ciudadano de primera clase y aflora en las fronteras Suspense y ErrorBoundary, y createAsync como el puente compatible hacia ese modelo. El giro mental de orquestar estados de carga y error a mano hacia escribir derivaciones que se leen como síncronas, y qué de tu código de hoy sobrevive intacto al salto.
Qué significa async transparente
Hoy, lo asíncrono es una isla dentro del grafo reactivo: un createResource o un createAsync marcan la frontera donde lo síncrono se encuentra con lo que tarda, y el resto del grafo —memos, efectos— vive en tierra firme, sin saber esperar. Solid 2.0 borra esa frontera. La ambición es que cualquier derivación pueda ser asíncrona: un createMemo podrá devolver una promesa, leer otra derivación que aún no resolvió, y el sistema entenderá que el resultado está pendiente sin que tú montes ninguna maquinaria.
La pieza clave es que lo pendiente deja de ser un booleano que administras y pasa a ser un estado que el grafo transporta solo. Cuando una derivación depende de un valor que aún no llegó, ella misma queda pendiente; y esa condición se propaga hacia arriba por las dependencias, exactamente igual que hoy se propaga un cambio de valor. El grafo ya sabía difundir “esto cambió”; en 2.0 sabe además difundir “esto todavía no está”.
// El modelo hacia el que se avanza: derivaciones que se encadenan// leyendose como sincronas, y el sistema gestiona la espera.const usuario = createAsync(() => getUsuario(id()));const inicial = () => usuario().nombre[0]; // se lee como sincronoconst saludo = () => `Hola, ${usuario().nombre}`;// nada de esto comprueba "cargando": lo pendiente fluye por el grafoLa consecuencia práctica es que las capas intermedias se evaporan. Hoy, entre la petición y la pantalla se interponen un recurso, un puñado de comprobaciones de loading y varios guardias contra el undefined; cada capa es código que escribes, pruebas y mantienes. En el modelo transparente esas capas desaparecen porque el grafo hace el trabajo: la derivación inicial ni sabe ni necesita saber que su fuente es asíncrona, y aun así quedará pendiente en cuanto lo esté usuario, arrastrando esa condición hacia la frontera sin una línea tuya de por medio.
El estado pendiente aflora en las fronteras
Si lo pendiente se propaga solo, ¿dónde se detiene y se hace visible? En las fronteras que ya usas. Cuando una porción del árbol depende de una derivación pendiente, esa condición sube por el grafo hasta el Suspense más cercano, que muestra su fallback; si en vez de tardar la promesa rechaza, el estado de error sube hasta el ErrorBoundary. No tienes que cablear nada: declaras las fronteras donde quieres que la carga y el fallo se materialicen, y el grafo enruta cada estado transitorio hasta ellas.
Esto ya lo viviste con createAsync en las lecciones anteriores, y esa es justo la señal de que vas por delante: el modelo de Solid 2.0 no es una API nueva que aprender, sino la generalización a todo el grafo de lo que hoy hace un primitivo del router. Lo que en 2026 es el comportamiento de createAsync —leer llamando, suspender hacia una frontera, rastrear como un memo— en 2.0 será el comportamiento de la reactividad a secas.
Hay una elegancia estructural en esto que conviene no pasar por alto: la misma frontera Suspense que hoy coordina la carga de tus datos coordinará la de cualquier derivación intermedia, sin que tengas que anticipar cuáles serán asíncronas. Colocas la frontera pensando en la experiencia —qué región debe mostrar un indicador mientras algo de su interior no está listo— y el grafo dirige hasta ella cualquier pendiente que surja debajo, hoy o tras un refactor futuro que vuelva async una derivación que antes no lo era.
// una frontera unica recoge lo pendiente de todo lo que hay debajo,// sin importar cuantas derivaciones intermedias resulten ser async<ErrorBoundary fallback={(e) => <Fallo err={e} />}> <Suspense fallback={<Cargando />}> <Panel />{/* si cualquier derivacion interior queda pendiente, cae aqui */} </Suspense></ErrorBoundary>Qué cambia en tu forma de escribir datos
El giro es mental antes que sintáctico. Durante años, escribir datos asíncronos significó orquestar estados: declarar cargando, declarar error, encadenar peticiones con banderas, sembrar la interfaz de guardias defensivos contra el undefined. El async transparente jubila ese oficio. Escribes una derivación que lee otras derivaciones como si sus valores estuvieran presentes, y delegas los estados transitorios a las fronteras. Piensas en qué depende de qué, no en cuándo llega cada cosa.
El cambio se nota en tres gestos concretos:
- Dejas de declarar signals de
cargandoyerror: esos estados suben a las fronteras. - Dejas de encadenar peticiones con banderas: encadenas leyendo un accessor dentro de otro.
- Dejas de sembrar guardias contra el
undefined: dentro de la frontera el valor siempre está.
// ANTES: orquestacion manual de estadosconst [datos, setDatos] = createSignal();const [cargando, setCargando] = createSignal(true);const [error, setError] = createSignal();createEffect(async () => { setCargando(true); try { setDatos(await pedir(id())); } catch (e) { setError(e); } finally { setCargando(false); }});// DESPUES: una derivacion que se lee como sincronaconst datos = createAsync(() => pedir(id()));// carga -> <Suspense> ; error -> <ErrorBoundary> ; valor -> datos()La buena noticia para tu código de hoy es que la migración ya empezó y es indolora. Todo lo que has escrito en este nivel —leer llamando, rastrear antes del await, componer sin cascadas, latest con transiciones— es exactamente el modelo de 2.0 en miniatura. Adoptar createAsync con query ahora no es apostar por una moda: es escribir el código que seguirá siendo idiomático cuando lo asíncrono baje del router al núcleo. La forma no cambiará; solo se hará universal.
Qué no tendrás que reaprender
El miedo razonable ante un cambio de versión mayor es tener que desaprender lo que ya dominas. Con el async transparente ocurre lo contrario: cuanto más idiomático sea hoy tu código con createAsync, menos notarás el salto. Repasa los hábitos de este nivel y comprobarás que cada uno es ya una pieza del modelo que viene.
- Leer llamando en vez de desestructurar una tupla: seguirá igual, solo que para cualquier derivación y no solo las del router.
- Rastrear antes del
await: la frontera del rastreo síncrono no se mueve; el grafo asíncrono la respeta idéntica. - Componer leyendo un accessor dentro de otro: es exactamente cómo se encadenarán las derivaciones async en el núcleo.
- Declarar carga y error en fronteras:
SuspenseyErrorBoundaryson las mismas piezas, ahora alimentadas por todo el grafo.
// este codigo de 2026 no cambia de forma cuando el async baje al nucleoconst usuario = createAsync(() => getUsuario(id()));const amigos = createAsync(() => getAmigosDe(usuario().id)); // encadenado, se lee sincrono// la carga sigue siendo un Suspense, el error un ErrorBoundary, la lectura una llamadaconst primero = () => amigos()[0]?.nombre ?? "sin amigos";Lo único que cambiará es de dónde importas el primitivo y cuánto abarca: lo que hoy es una capacidad de la librería de rutas, mañana será una propiedad de la reactividad misma. El gesto de tu mano sobre el teclado no se moverá una pulgada.