Volver al blog

Signals en JavaScript: La Propuesta TC39 Que Podria Traer Reactividad Nativa al Lenguaje

Hola HaWkers, una propuesta que esta ganando momentum en TC39 podria cambiar fundamentalmente como construimos interfaces reactivas en JavaScript. Signals, un primitivo de reactividad ya usado por Angular, Vue, Solid y Svelte, esta siendo considerado para inclusion en la especificacion oficial de ECMAScript.

Si trabajas con frontend moderno, esta propuesta merece tu atencion. Vamos a entender que son Signals, como funciona la propuesta y que significa esto para el futuro del desarrollo web.

Que Son Signals

Signals son primitivos de reactividad que permiten crear valores que automaticamente notifican a los dependientes cuando cambian. Piensa en ellos como variables inteligentes que saben quien las esta usando.

El Concepto Basico

La idea fundamental es simple pero poderosa:

// Pseudocodigo ilustrativo del concepto
const count = signal(0);        // Crea un signal con valor inicial 0
const doubled = computed(() => count.value * 2);  // Derivado automaticamente

console.log(doubled.value);     // 0
count.value = 5;                // Cambia el signal
console.log(doubled.value);     // 10 - automaticamente actualizado

Por Que Importan los Signals

Problemas que Signals resuelven:

  1. Actualizaciones granulares: En lugar de re-renderizar componentes enteros, solo lo que depende del valor cambia

  2. Sincronizacion automatica: Los valores derivados son siempre consistentes con sus fuentes

  3. Performance predecible: El sistema sabe exactamente que necesita actualizar

  4. Simplicidad de modelo mental: Menos conceptos que sistemas como Redux

La Propuesta TC39

La propuesta de Signals para JavaScript esta siendo desarrollada colaborativamente entre representantes de varios frameworks.

Quien Esta Involucrado

Autores de la propuesta:

  • Rob Eisenberg (Microsoft/Angular)
  • Daniel Ehrenberg (Bloomberg/Igalia)
  • Contribuciones de maintainers de Vue, Solid, Svelte

Objetivo declarado:

"Crear una base comun de reactividad que permita interoperabilidad entre frameworks y reduzca duplicacion de codigo."

Lo Que Incluye La Propuesta

La propuesta define dos primitivos principales:

Signal.State:

// Signal basico que guarda un valor
const counter = new Signal.State(0);

// Leyendo el valor
console.log(counter.get()); // 0

// Escribiendo el valor
counter.set(counter.get() + 1);
console.log(counter.get()); // 1

Signal.Computed:

const firstName = new Signal.State("John");
const lastName = new Signal.State("Doe");

// Computed que deriva de otros signals
const fullName = new Signal.Computed(() => {
  return `${firstName.get()} ${lastName.get()}`;
});

console.log(fullName.get()); // "John Doe"

firstName.set("Jane");
console.log(fullName.get()); // "Jane Doe" - actualizado automaticamente

Lo Que NO Esta En La Propuesta

Importante entender los limites:

No incluido:

  • Sistema de efectos (side effects)
  • Batching automatico
  • Integracion con DOM
  • Scheduling de actualizaciones

Por que?

"La propuesta es intencionalmente minimal para permitir que frameworks implementen sus propias semanticas sobre la base comun."

Como Frameworks Ya Usan Signals

Para entender la propuesta, es util ver como frameworks existentes implementan reactividad.

Angular Signals

Angular adopto Signals oficialmente en versiones recientes:

import { signal, computed, effect } from '@angular/core';

@Component({
  template: `
    <button (click)="increment()">
      Count: {{ count() }}
    </button>
    <p>Double: {{ doubleCount() }}</p>
  `
})
export class CounterComponent {
  count = signal(0);
  doubleCount = computed(() => this.count() * 2);

  increment() {
    this.count.update(value => value + 1);
  }

  constructor() {
    effect(() => {
      console.log(`Count changed to: ${this.count()}`);
    });
  }
}

Vue Reactivity

Vue 3 usa un sistema similar llamado refs:

import { ref, computed, watchEffect } from 'vue';

const count = ref(0);
const doubled = computed(() => count.value * 2);

watchEffect(() => {
  console.log(`Count is now: ${count.value}`);
});

// En template: {{ count }} y {{ doubled }}

SolidJS Signals

SolidJS fue pionero en signals para el frontend:

import { createSignal, createEffect, createMemo } from 'solid-js';

function Counter() {
  const [count, setCount] = createSignal(0);
  const doubled = createMemo(() => count() * 2);

  createEffect(() => {
    console.log(`Count changed to: ${count()}`);
  });

  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count()} | Doubled: {doubled()}
    </button>
  );
}

Beneficios de la Estandarizacion

Por que incluir Signals en el lenguaje en lugar de dejarlo como esta?

Interoperabilidad Entre Frameworks

Actualmente, signals de diferentes frameworks son incompatibles:

Problema actual:

  • Un signal de Angular no funciona en Vue
  • Componentes de diferentes frameworks no comparten estado
  • Bibliotecas necesitan elegir cual sistema soportar

Con estandarizacion:

  • Base comun permitiria interoperabilidad
  • Bibliotecas podrian trabajar con cualquier framework
  • Migracion entre frameworks seria mas simple

Reduccion de Bundle Size

Cada framework carga su propia implementacion de reactividad:

Tamano actual de implementaciones:

  • Angular Signals: ~8KB
  • Vue Reactivity: ~12KB
  • SolidJS: ~7KB
  • Preact Signals: ~3KB

Con implementacion nativa:

  • Cero KB adicional (parte del runtime)
  • Optimizaciones de engine posibles
  • Performance potencialmente mejor

Modelo Mental Unificado

Los desarrolladores aprenden el concepto una vez:

Actualmente:

  • Cada framework tiene nomenclatura diferente
  • APIs varian (get/set vs .value vs funcion)
  • Comportamientos sutilmente diferentes

Con estandar:

  • Un concepto, una API
  • Documentacion centralizada
  • Transferencia de conocimiento simplificada

Desafios y Controversias

La propuesta no es unanime. Existen debates importantes en la comunidad.

El Debate React

React no usa Signals internamente:

Posicion del equipo React:

  • Prefieren modelo de inmutabilidad
  • Signals pueden incentivar mutacion
  • Complejidad adicional para casos de uso de React

Contraargumento:

  • React podria implementar capa sobre Signals
  • No es obligatorio usar, solo disponible
  • Otros patterns tambien existen (clases, closures)

Complejidad de la Especificacion

Algunos argumentan que Signals son muy opinados para el lenguaje:

Preocupaciones:

  • JavaScript nunca tuvo primitivos de UI antes
  • Puede incentivar patterns especificos
  • Implementacion de engine es compleja

Respuesta de los autores:

  • Signals son utiles mas alla de UI (observables, data sync)
  • Propuesta es minimal y extensible
  • Ya existen primitivos complejos (Proxy, WeakMap)

Performance En Casos Extremos

Sistemas reactivos pueden tener overhead:

Problemas potenciales:

  • Tracking de dependencias tiene costo
  • Muchos signals = mucha memoria
  • Cascadas de actualizaciones

Mitigaciones propuestas:

  • Evaluacion lazy por defecto
  • Batching de notificaciones
  • Referencias debiles para cleanup

Ejemplo Practico: Implementando Un Formulario

Ve como Signals nativos podrian funcionar en un escenario real:

// Con la propuesta, seria algo asi:
const form = {
  email: new Signal.State(''),
  password: new Signal.State(''),
  confirmPassword: new Signal.State('')
};

// Validaciones derivadas
const emailValid = new Signal.Computed(() => {
  const email = form.email.get();
  return email.includes('@') && email.includes('.');
});

const passwordsMatch = new Signal.Computed(() => {
  return form.password.get() === form.confirmPassword.get();
});

const formValid = new Signal.Computed(() => {
  return emailValid.get() &&
         form.password.get().length >= 8 &&
         passwordsMatch.get();
});

// Uso en framework ficticio
function renderForm() {
  return html`
    <form>
      <input
        type="email"
        value=${form.email.get()}
        oninput=${e => form.email.set(e.target.value)}
        class=${emailValid.get() ? 'valid' : 'invalid'}
      />

      <input
        type="password"
        value=${form.password.get()}
        oninput=${e => form.password.set(e.target.value)}
      />

      <input
        type="password"
        value=${form.confirmPassword.get()}
        oninput=${e => form.confirmPassword.set(e.target.value)}
        class=${passwordsMatch.get() ? '' : 'error'}
      />

      <button disabled=${!formValid.get()}>
        Submit
      </button>
    </form>
  `;
}

Timeline y Estado Actual

Donde esta la propuesta en el proceso del TC39.

Etapa Actual

Estado: Stage 1 (Proposal)

Esto significa:

  • El comite concuerda que el problema vale resolver
  • La propuesta esta siendo activamente desarrollada
  • Todavia hay cambios significativos posibles
  • No esta lista para implementacion

Proximos Pasos

Para Stage 2:

  • Especificacion inicial completa
  • Semantica bien definida
  • Ejemplo de implementacion

Para Stage 3:

  • Implementacion en al menos un engine
  • Feedback de uso real
  • Especificacion estable

Para Stage 4:

  • Multiples implementaciones
  • Tests de conformidad
  • Aprobacion final

Prediccion Conservadora

Timeline estimada:

  • 2026: Refinamiento de la propuesta
  • 2027: Posible Stage 2/3
  • 2028+: Implementaciones en navegadores
  • 2029+: Uso en produccion seguro

Como Prepararse

Aunque la propuesta tarde, puedes prepararte.

Aprende Signals Ahora

Usa una de las implementaciones existentes:

// Preact Signals - muy similar a la propuesta
import { signal, computed, effect } from '@preact/signals';

const count = signal(0);
const doubled = computed(() => count.value * 2);

effect(() => {
  console.log(doubled.value);
});

Entiende Los Fundamentos

Conceptos que transfieren a cualquier implementacion:

  • Tracking de dependencias automatico
  • Evaluacion lazy vs eager
  • Batching y scheduling
  • Cleanup y lifecycle

Reflexion Final

La propuesta de Signals en TC39 representa una posible evolucion fundamental de JavaScript para aplicaciones reactivas. Unificar como frameworks manejan reactividad podria simplificar el ecosistema y mejorar la interoperabilidad.

Los puntos clave:

  • Signals son primitivos de reactividad ya probados en frameworks
  • La propuesta TC39 busca estandarizacion, no reemplazo de frameworks
  • Beneficios incluyen interoperabilidad y reduccion de codigo
  • Timeline es larga - probablemente 2028+ para uso en produccion
  • Aprender signals ahora te prepara para el futuro

Independiente de cuando (o si) la propuesta sea aprobada, entender reactividad basada en signals ya es valioso hoy. Angular, Vue, Solid y otros frameworks ya adoptaron el pattern, y la tendencia continua creciendo.

Si quieres explorar mas sobre las novedades de JavaScript moderno, te recomiendo que eches un vistazo a otro articulo: ES2026: Las Nuevas Features Que Van a Cambiar Tu Codigo donde descubriras otras propuestas importantes en desarrollo.

Vamos para arriba! 🦅

Comentarios (0)

Este artículo aún no tiene comentarios 😢. ¡Sé el primero! 🚀🦅

Añadir comentarios