preloader

Decoradores y caché transparente en JavaScript

Decoradores y caché transparente

JavaScript ofrece una gran flexibilidad en cuanto a funciones. Puedes pasarlas como objetos y modificar su comportamiento de varias maneras, como veremos a continuación.

Caché de resultados

Imagina una función slow(x) que realiza operaciones intensivas en la CPU pero siempre devuelve el mismo resultado para un mismo x.

Si esta función se llama frecuentemente con los mismos argumentos, sería eficiente almacenar en caché los resultados para evitar cálculos repetidos.

En lugar de modificar directamente slow(), podemos crear un «decorador» que agregue la funcionalidad de caché. Esto tiene sus ventajas, como veremos.

Aquí tienes el código con una explicación detallada:

				
					function slow(x) {
  // Código intensivo en CPU
  alert(`Llamada con ${x}`);
  return x;
}

function cachingDecorator(func) {
  let cache = new Map();

  return function(x) {
    if (cache.has(x)) {
      return cache.get(x);
    }

    let result = func(x);
    cache.set(x, result);
    return result;
  };
}

slow = cachingDecorator(slow);

alert( slow(1) ); // El resultado de slow(1) se almacena en caché y se devuelve
alert( "Otra vez: " + slow(1) ); // Se devuelve el resultado de la caché de slow(1)

alert( slow(2) ); // El resultado de slow(2) se almacena en caché y se devuelve
alert( "Otra vez: " + slow(2) ); // Se devuelve el resultado de la caché de slow(2)

				
			
  • En este ejemplo, cachingDecorator es un decorador: una función especial que toma otra función y la envuelve para modificar su comportamiento.

    La idea es que podemos aplicar cachingDecorator a cualquier función para agregarle la funcionalidad de caché. Esto es útil ya que podemos reutilizar el decorador con diferentes funciones y mantener el código más simple.

    Usando func.call para el contexto

    El decorador de caché que hemos visto hasta ahora no funciona bien con métodos de objetos.

    Por ejemplo, considera el siguiente código donde queremos cachear el método worker.slow():

				
					let worker = {
  someMethod() {
    return 1;
  },

  slow(x) {
    alert("Llamada con " + x);
    return x * this.someMethod(); // Error aquí: `this` no está definido
  }
};

function cachingDecorator(func) {
  let cache = new Map();

  return function(x) {
    if (cache.has(x)) {
      return cache.get(x);
    }

    let result = func.call(this, x); // Solución: usar `func.call` para establecer correctamente `this`
    cache.set(x, result);
    return result;
  };
}

worker.slow = cachingDecorator(worker.slow);

alert( worker.slow(2) ); // Funciona correctamente ahora
alert( worker.slow(2) ); // Se devuelve el resultado de la caché

				
			

En este caso, func.call(this, x) asegura que la función original se llame con el contexto correcto (this). Esto es esencial para que los métodos de objetos funcionen correctamente con decoradores.

Manejo de múltiples argumentos

Para manejar funciones con múltiples argumentos, necesitamos modificar nuestro decorador para que funcione con cualquier número de argumentos. Aquí tienes una versión mejorada:

				
					let worker = {
  slow(min, max) {
    alert(`Llamada con ${min},${max}`);
    return min + max; // Operación intensiva en CPU
  }
};

function cachingDecorator(func) {
  let cache = new Map();

  return function() {
    let key = [].join.call(arguments, ',');
    if (cache.has(key)) {
      return cache.get(key);
    }

    let result = func.apply(this, arguments);
    cache.set(key, result);
    return result;
  };
}

worker.slow = cachingDecorator(worker.slow);

alert( worker.slow(3, 5) ); // Funciona correctamente
alert( "Otra vez: " + worker.slow(3, 5) ); // Se devuelve el resultado de la caché

				
			

En este ejemplo, func.apply(this, arguments) se utiliza para pasar todos los argumentos y el contexto correcto (this) a la función original dentro del decorador.

Resumen

Los decoradores en JavaScript permiten agregar funcionalidades adicionales a las funciones sin modificar su código interno. Esto los hace reutilizables y mantiene el código más modular y fácil de mantener.

Related Post

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *