Memoización: rendimiento del código

Mar 02 2023
¿Qué es Memoización? La memorización es una técnica utilizada en la programación de computadoras para optimizar el rendimiento de funciones llamadas repetidamente con los mismos argumentos de entrada. La idea es almacenar en caché los resultados de llamadas a funciones anteriores y devolver el resultado almacenado en caché en lugar de volver a calcular el resultado cuando se llama a la función con los mismos argumentos.

¿Qué es Memoización?

La memorización es una técnica utilizada en la programación de computadoras para optimizar el rendimiento de funciones llamadas repetidamente con los mismos argumentos de entrada. La idea es almacenar en caché los resultados de llamadas a funciones anteriores y devolver el resultado almacenado en caché en lugar de volver a calcular el resultado cuando se llama a la función con los mismos argumentos.

En JavaScript

Puede implementar la memorización creando un objeto de caché y usándolo para almacenar los resultados de llamadas a funciones anteriores. Aquí hay un ejemplo de cómo implementar la memorización en JavaScript:

function memoize(func) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache[key]) {
      return cache[key];
    } else {
      const result = func.apply(this, args);
      cache[key] = result;
      return result;
    }
  };
}

Dentro de la función devuelta, creamos una cadena keyusando JSON.stringifypara serializar los argumentos de entrada. Comprobamos si la clave existe en el objeto de caché y, si existe, devolvemos el resultado almacenado en caché. De lo contrario, llamamos a la función original con los argumentos de entrada usando el applymétodo, almacenamos el resultado en el objeto de caché y devolvemos el resultado.

Aquí hay un ejemplo de cómo usar la memoizefunción para memorizar una función de Fibonacci simple:

const fibonacci = memoize(function(n) {
  if (n <= 1) {
    return n;
  } else {
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
});

console.log(fibonacci(10)); // 55
console.log(fibonacci(10)); // 55 (cached result)

NodeJS + Redis = Rendimiento mejorado

Node.js es un tiempo de ejecución de JavaScript del lado del servidor que proporciona un modelo de programación asíncrono basado en eventos. Redis es un almacén de estructura de datos en memoria de código abierto que a menudo se usa como base de datos, caché y agente de mensajes. En Node.js, puede usar Redis para almacenar y recuperar datos en la memoria, lo que puede ayudar a mejorar el rendimiento de su aplicación.

Aquí hay un ejemplo para que comprenda el rendimiento cuando se utiliza la técnica de almacenamiento en caché. Y a continuación, pasaremos a un código más práctico. Primero, instalaremos los paquetes npm:

npm install express body-parser mongoose redis --save

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const redis = require('redis');

const app = express();

app.use(bodyParser.json());

// connect to redis, use default port and address
const client = redis.createClient('redis://127.0.0.1:6379');
client.on("error", (err) => {
console.error(err);
});

// MongoDB connection
mongoose.connect('mongodb://localhost:27017/', {
dbName: 'notes',
useNewUrlParser: true,
useUnifiedTopology: true
}, err => err ? console.log(err) : console.log('Connected to database'));

// Mongoose Model
const NoteSchema = new mongoose.Schema({
title: String,
note: String
});

const Note = mongoose.model('Note', NoteSchema);

// api post a note
app.post('/api/notes', (req, res, next) => {const { title, note } = req.body;

const _note = new Note({
    title: title,
    note: note
});
// save to MongoDB
_note.save((err, note) => {
    if (err) {
        return res.status(404).json(err);
    }

    // If successful in MongoDB, then add it to Redis
    client.setex(note.id, 60, JSON.stringify(note), (err, reply) => {
        if (err) {
            console.log(err);
        }
        console.log(reply);
    });

    return res.status(201).json({
        message: 'Note has been saved',
        note: note
    });
})
});
const isCached = (req, res, next) => {
const { id } = req.params;

// First check in Redis
client.get(id, (err, data) => {
    if (err) {
        console.log(err);
    }
    if (data) {
        const response = JSON.parse(data);
        return res.status(200).json(response);
    }
    next();
});
}
// When retrieving, we will get it from Redis first instead of accessing MongoDB to get this data.
app.get('/api/notes/:id', isCached, (req, res, next) => {
const { id } = req.params;

Note.findById(id, (err, note) => {
    if (err) {
        return res.status(404).json(err);
    }
    return res.status(200).json({
        note: note
    });
});
});

app.listen(3000, () => console.log('Server running at port 3000'));

En las líneas de código anteriores, prestamos atención a la configuración y obtención de Redis:

client.setex(note.id, 60, JSON.stringify(note), (err, reply) => {
if (err) {
console.log(err);
}
console.log(reply);
});

segundos: tiempo de caducidad en segundos como un número.

valor: datos reales para almacenar en Redis. Debe ser una cadena. Así que estamos serializando objetos en cadenas.

callback: Callback toma dos parámetros err y answer.

Y al recuperar un documento, irá a isCached() para recuperarlo. Si hay algún problema, como que el tiempo de caché haya expirado, continuará recuperando datos en MongoDB.

app.get('/api/notes/:id', isCached, (req, res, next) => {

scss
Copy code
const { id } = req.params;

Note.findById(id, (err, note) => {
    if (err) {
        return res.status(404).json(err);
    }
    return res.status(200).json({
        note: note
    });
});
});