"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Competir con JSON.stringify: creando uno personalizado

Competir con JSON.stringify: creando uno personalizado

Publicado el 2024-08-20
Navegar:328

Competing with JSON.stringify - by building a custom one

Esto surgió durante una discusión con mi amigo sobre la recursión. ¿Por qué no construir
¿Un método Javascript JSON.stringify como ejercicio de programación recursiva? Me parece genial
idea.

Rápidamente redacté la primera versión. ¡Y funcionó horriblemente! El
el tiempo requerido fue aproximadamente 4 veces mayor que el del estándar JSON.stringify.

el primer borrador

function json_stringify(obj) {
  if (typeof obj == "number" || typeof obj == "boolean") {
    return String(obj);
  }

  if (typeof obj == "string") {
    return `"${obj}"`;
  }

  if (Array.isArray(obj)) {
    return "["   obj.map(json_stringify).join(",")   "]";
  }

  if (typeof obj === "object") {
    const properties_str = Object.entries(obj)
      .map(([key, val]) => {
        return `"${key}":${json_stringify(val)}`;
      })
      .join(",");
    return "{"   properties_str   "}";
  }
}

Al ejecutar lo siguiente, podemos ver que nuestro json_stringify funciona como
esperado.

const { assert } = require("console");
const test_obj = {
  name: "John Doe",
  age: 23,
  hobbies: ["football", "comet study"]
};

assert(json_stringify(test_obj) === JSON.stringify(test_obj))

Para probar más escenarios y múltiples ejecuciones para tener una idea promedio de cómo funciona nuestro
ejecución del script, creamos un script de prueba simple.

Un script de prueba simple

function validity_test(fn1, fn2, test_values) {
  for (const test_value of test_values) {
    assert(fn1(test_value) == fn2(test_value));
  }
}

function time(fn, num_runs = 1, ...args) {
  const start_time = Date.now()

  for (let i = 0; i 


Al ejecutar esto obtenemos tiempos como los siguientes.

Testing 1000 times
    Std lib JSON.stringify() took 5 ms
    Custom json_stringify() took 20 ms
Testing 10000 times
    Std lib JSON.stringify() took 40 ms
    Custom json_stringify() took 129 ms
Testing 100000 times
    Std lib JSON.stringify() took 388 ms
    Custom json_stringify() took 1241 ms
Testing 1000000 times
    Std lib JSON.stringify() took 3823 ms
    Custom json_stringify() took 12275 ms

Puede que se ejecute de manera diferente en diferentes sistemas, pero la proporción del tiempo necesario
por std JSON.strngify al de nuestro json_stringify personalizado debería ser aproximadamente
1:3 - 1:4

También podría ser diferente en un caso interesante. Continúe leyendo para saber más sobre
¡eso!

Mejorando el rendimiento

Lo primero que se podría arreglar es el uso de la función de mapa. Crea
nueva matriz de la anterior. En nuestro caso de objetos, está creando una matriz de
Propiedades de objeto encadenadas JSON fuera de la matriz que contiene entradas de objeto.

Algo similar también está sucediendo con la encadenación de los elementos de la matriz.

¡Tenemos que recorrer los elementos de una matriz o las entradas de un objeto! Pero
podemos omitir la creación de otra matriz solo para unir las partes encadenadas JSON.

Aquí está la versión actualizada (solo se muestran las partes modificadas por brevedad)

function json_stringify(val) {
  if (typeof val === "number" || typeof val === "boolean") {
    return String(val);
  }

  if (typeof val === "string") {
    return `"${val}"`;
  }

  if (Array.isArray(val)) {
    let elements_str = "["

    let sep = ""
    for (const element of val) {
      elements_str  = sep   json_stringify(element)
      sep = ","
    }
    elements_str  = "]"

    return elements_str
  }

  if (typeof val === "object") {
    let properties_str = "{"

    let sep = ""
    for (const key in val) {
      properties_str  = sep   `"${key}":${json_stringify(val[key])}`
      sep = ","
    }
    properties_str  = "}"

    return properties_str;
  }
}

Y aquí está el resultado del script de prueba ahora

Testing 1000 times
        Std lib JSON.stringify() took 5 ms
        Custom json_stringify() took 6 ms
Testing 10000 times
        Std lib JSON.stringify() took 40 ms
        Custom json_stringify() took 43 ms
Testing 100000 times
        Std lib JSON.stringify() took 393 ms
        Custom json_stringify() took 405 ms
Testing 1000000 times
        Std lib JSON.stringify() took 3888 ms
        Custom json_stringify() took 3966 ms

Esto se ve mucho mejor ahora. Nuestro json_stringify personalizado tarda solo 3 ms
más que JSON.stringify para encadenar un objeto anidado profundo 10.000 veces.
Aunque esto no es perfecto, es un retraso aceptable.

¿Exprimir más?

El retraso actual podría deberse a toda la creación y concatenación de cadenas
eso está pasando. Cada vez que ejecutamos elements_str = sep json_stringify(element)
estamos concatenando 3 cadenas.

Concatenar cadenas es costoso porque requiere

  1. creando un nuevo búfer de cadena para que quepa toda la cadena combinada
  2. copiar cadenas individuales al búfer recién creado

Al usar un Buffer nosotros mismos y escribir los datos directamente allí, podríamos obtener
una mejora del rendimiento. Dado que podemos crear un búfer grande (digamos 80 caracteres)
y luego cree nuevos buffers para que quepan 80 caracteres más cuando se agote.

No evitaremos la reasignación/copia de datos por completo, pero lo haremos
reduciendo esas operaciones.

¡Otro posible retraso es el proceso recursivo en sí! Específicamente el
llamada a función que consume tiempo. Considere nuestra llamada a función json_stringify(val)
que solo tiene un parámetro.

Comprender las llamadas a funciones

Los pasos serían

  1. Enviar la dirección del remitente a la pila
  2. enviar la referencia del argumento a la pila
  3. En la función llamada
    1. Saque la referencia del parámetro de la pila
    2. Extrae la dirección del remitente de la pila
    3. empuje el valor de retorno (la parte encadenada) a la pila
  4. En la función de llamada
    1. Extraiga el valor devuelto por la función de la pila

Todas estas operaciones se realizan para garantizar que se realicen llamadas a funciones y esto agrega CPU
costos.

Si creamos un algoritmo no recursivo de json_stringify todas estas operaciones
enumerado anteriormente para llamadas a funciones (multiplicadas por el número de dichas llamadas) sería
reducido a ninguno.

Este puede ser un intento futuro.

Diferencias de versión de NodeJs

Una última cosa a tener en cuenta aquí. Considere el siguiente resultado del script de prueba

Testing 1000 times
        Std lib JSON.stringify() took 8 ms
        Custom json_stringify() took 8 ms
Testing 10000 times
        Std lib JSON.stringify() took 64 ms
        Custom json_stringify() took 51 ms
Testing 100000 times
        Std lib JSON.stringify() took 636 ms
        Custom json_stringify() took 467 ms
Testing 1000000 times
        Std lib JSON.stringify() took 6282 ms
        Custom json_stringify() took 4526 ms

¿Nuestro json_stringify personalizado funcionó mejor que el estándar NodeJs?
JSON.stringify???

¡Pues sí! Pero esta es una versión anterior de NodeJs (v18.20.3). Resulta que para
En esta versión (y quizás también en versiones inferiores), nuestro json_stringify personalizado funciona
¡Más rápido que la biblioteca estándar!

Todas las pruebas de este artículo (excepto esta última) se han realizado con
Nodo v22.6.0

El rendimiento de JSON.stringify ha aumentado de v18 a v22. Esto es genial

También es importante tener en cuenta que nuestro script funcionó mejor en NodeJs v22.
Entonces, significa que NodeJs también ha aumentado el rendimiento general del tiempo de ejecución.
Posiblemente se haya producido una actualización en el motor V8 subyacente.

Bueno, esta ha sido una experiencia agradable para mí. Y espero que sea para
tú también. ¡Y en medio de todo este disfrute, aprendimos un par de cosas!

¡Sigue construyendo, sigue probando!

Declaración de liberación Este artículo se reproduce en: https://dev.to/riturajborpujari/competing-with-jsonstringify-by-building-a-custom-one-53l5?1 Si hay alguna infracción, comuníquese con [email protected] para eliminar él
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3