¿Qué hay de nuevo en Node.js 15?

Compartimos la traducción del artículo, que contiene detalles sobre las nuevas características de la 15a versión de Node.js.


La versión 15 de Node.js se lanzó el 20 de octubre de 2020. Los cambios importantes incluyen:



  • modo de lanzamiento en desviaciones no controladas
  • características del idioma V8 8.6
  • NPM 7
  • soporte QUIC experimental
  • N-API Versión 7
  • finalización de la API de almacenamiento local Async


Echemos un vistazo más de cerca a qué son estas innovaciones y cómo se pueden utilizar.



Uso de NVM para la descripción general del nodo



En el artículo anterior, repasamos las instrucciones para usar NVM (Node Version Manager) para administrar versiones de Node.js y NPM. Tenemos Node.js 12.16.0 y NPM 6.14.8 instalados en nuestro entorno. Al ejecutar nvm install node , hemos instalado Node.js 15.4.0 y NPM7.0.15.



Tenemos dos ventanas abiertas, una con Node.js 12 y la otra con Node.js 15.



En la ventana de node12 :



$ nvm use 12
Now using node v12.16.0 (npm v6.14.8)
      
      





En la ventana del nodo15 :



$ nvm use 15
Now using node v15.4.0 (npm v7.0.15)
      
      





Ahora podemos investigar esta versión.



Modo de lanzamiento en caso de rechazo de promesa no controlada



El evento unhandledRejection se genera cada vez que se rechaza una promesa y no se adjunta un controlador de errores a la promesa durante el ciclo de eventos. A partir de Node.js 15, el modo predeterminado para unhandledRejection ha cambiado de advertir a lanzar . En el modo de lanzamiento , si no se establece el gancho unhandledRejection , el unhandledRejection se lanza como una excepción no detectada por el método catch .



Cree un programa para rechazar la promesa con un mensaje de error:



function myPromise() {
  new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: 'The call is rejected with an error',
        }),
      1000
    )
  ).then((data) => console.log(data.data));
}

myPromise();
      
      





Cuando ejecuta este código en una ventana de node12 , aparece un mensaje de advertencia largo:



$ node myPromise.js
(node:79104) UnhandledPromiseRejectionWarning: #<Object>
(node:79104) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:79104) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.Users that have an unhandledRejection hook should see no change in behavior, and it’s still possible to switch modes using the --unhandled-rejections=mode process flag.
      
      





Ejecutar este código en la ventana node15 genera un error UnhandledPromiseRejection :



$ node myPromise.js
node:internal/process/promises:227
          triggerUncaughtException(err, true /* fromPromise */);
          ^[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#<Object>".] {
  code: 'ERR_UNHANDLED_REJECTION'
}
      
      





Agregue un controlador de errores a la rama then en el código siguiente ( .catch (( error ) => console.log ( error .error)) también funciona).



function myPromise() {
  new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: 'The call is rejected with an error',
        }),
      1000
    )
  ).then(
    (data) => console.log(data.data),
    (error) => console.log(error.error)
  );
}

myPromise();
      
      





Ahora el código se ejecuta correctamente en ambas ventanas ( nodo12 y nodo15 ):



$ node myPromise.js
The call is rejected with an error
      
      





Se recomienda escribir un controlador de errores para las promesas. Sin embargo, puede haber casos en los que el método de captura no detecta los errores. Se recomienda configurar el gancho unhandledRejection para detectar posibles errores.



function myPromise() {
  new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: 'The call is rejected with an error',
        }),
      1000
    )
  ).then((data) => console.log(data.data));
}

myPromise();

process.on('unhandledRejection', (reason, promise) => {
  console.log('reason is', reason);
  console.log('promise is', promise);
  // Application specific logging, throwing an error, or other logic here
});
      
      





El gancho unhandledRejection funciona tanto en Node.js 12 como en Node.js 15. Una vez instalado, el unhandledRejection se maneja según sea necesario.



$ node myPromise.js
reason is { error: 'The call is rejected with an error' }
promise is Promise { <rejected> { error: 'The call is rejected with an error' } }
      
      





V8 8.6 Nuevas funciones de idioma



V8, motor JavaScript, actualizado de 8.4 a 8.6. versión. Además de varios ajustes para mejorar el rendimiento, el nuevo V8 tiene las siguientes características:



  • Promise.any () y AggregateError (de V8 8.5)
  • await setTimeout y AbortController (experimental)
  • String.prototype.replaceAll () (desde V8 8.5)
  • Operadores de asignación lógica && = , || = y ?? = (de V8 8.5)


Promise.any () y AggregateError



Primero, echemos un vistazo al método Promise.all () existente .



Promise.all () toma un iterable de promesas como entrada y devuelve una única promesa, que se ejecuta como una matriz de los resultados de las promesas de entrada.



El siguiente programa llama a Promise.all () en dos promesas resueltas:



function myPromise(delay) {
  return new Promise((resolve) =>
    setTimeout(
      () =>
        resolve({
          data: The data from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.all([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

getData();

      
      





Promise.all () devuelve una promesa que se cumplirá cuando se resuelvan todas las promesas de entrada, o si el iterable no contiene promesas:



$ node myPromise.js
[
  { data: 'The data from 5000 ms delay' },
  { data: 'The data from 100 ms delay' }
]
      
      





El siguiente programa llama a Promise.all () en dos promesas rechazadas.



function myPromise(delay) {
  return new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: The error from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.all([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

getData();
      
      





Promise.all () rechaza inmediatamente cualquier rechazo de la promesa de entrada o cualquier error en el momento de la ejecución, devolviendo un mensaje sobre este error:



$ node myPromise.js
{ error: 'The error from 100 ms delay' }
      
      





Promise.any () es un nuevo método en Node.js 15. Es lo opuesto a Promise.all () . Promise.any () acepta un iterable que contiene objetos Promise. Y, tan pronto como una de las Promesas en el iterable tenga éxito, el método devolverá una única promesa con el valor de la promesa cumplida.



El siguiente programa llama a Promise.any () en dos promesas resueltas:



function myPromise(delay) {
  return new Promise((resolve) =>
    setTimeout(
      () =>
        resolve({
          data: The error from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.any([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
    console.log(error.errors);
  }
}

getData();
      
      





Promise.any () devuelve la primera promesa resuelta:



$ node myPromise.js
{ data: 'The error from 100 ms delay' }
      
      





El siguiente programa llama a Promise.any () en dos promesas rechazadas:



function myPromise(delay) {
  return new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: The error from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.any([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
    console.log(error.errors);
  }
}

getData();
      
      





Si las promesas en el iterable fallan, es decir todas las promesas dadas se rechazan, la promesa devuelta se rechaza con AggregateError , una nueva subclase de Error que agrupa los errores individuales.



$ node myPromise.js
[AggregateError: All promises were rejected]
[
  { error: 'The error from 5000 ms delay' },
  { error: 'The error from 100 ms delay' }
]
      
      





Espere setTimeout y AbortController



En los ejemplos anteriores, usamos setTimeout dentro de una llamada de promesa.



SetTimeout en WindowOrWorkerGlobalScope usa una devolución de llamada. Sin embargo, los temporizadores / promesas proporcionan una versión prometida de setTimeout que se puede usar con async / await.



const { setTimeout } = require('timers/promises');

async function myPromise(delay) {
  await setTimeout(delay);
  return new Promise((resolve) => {
    resolve({
      data: The data from ${delay} ms delay,
    });
  });
}

async function getData() {
  try {
    const data = await Promise.any([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
    console.log(error.errors);
  }
}

getData();
      
      





AbortController es un objeto de JavaScript que le permite cancelar una o más solicitudes web a voluntad. Hemos proporcionado ejemplos del uso de AbortController en otro artículo sobre useAsync .



Tanto await setTimeout como AbortController son funciones experimentales.



String.prototype.replaceAll ()



Echemos un vistazo al método String.prototype.replace () existente .



replace () devuelve una nueva cadena con algunas o todas las coincidencias de patrones reemplazadas con el reemplazador. El patrón puede ser una cadena o una expresión regular. El marcador de posición puede ser una cadena o una función que se llama para cada coincidencia.



Si el patrón es una cadena, solo se reemplazará la primera aparición.



'20+1+2+3'.replace('+', '-');
      
      





El uso de este operador dará “20–1 + 2 + 3” .



Para reemplazar todo "+" por "-", debe usar una expresión regular.



'20+1+2+3'.replace(/\+/g, '-');
      
      





El uso del operador anterior dará "20-1-2-3" .



El método replaceAll () es nuevo en Node.js 15. Al usarlo, no tenemos que usar una expresión regular. Este método devuelve una nueva cadena con todas las coincidencias de patrones reemplazadas con el marcador de posición. El patrón puede ser una cadena o una expresión regular, y el marcador de posición puede ser una cadena o una función llamada para cada coincidencia.



Gracias al método replaceAll () , no tenemos que usar una expresión regular para reemplazar todo "+" con "-".



'20+1+2+3'.replaceAll('+', '-');
      
      





La ejecución de este operador da "20-1-2-3" .



Operadores de asignación lógica && =, || = y ?? =



El operador de asignación lógica AND ( x && = y ) realiza una operación de asignación solo si x es verdadera.



x && = y es equivalente a x && (x = y) , pero no equivalente a x = x && y .



let x = 0;
let y = 1;

x &&= 0; // 0
x &&= 1; // 0
y &&= 1; // 1
y &&= 0; // 0
      
      





El operador de asignación lógica OR (x || = y) realiza una operación de asignación solo si x es falso.



x || = y es equivalente ax || (x = y) pero no equivalente ax = x || en .



let x = 0;
let y = 1;

x ||= 0; // 0
x ||= 1; // 1
y ||= 1; // 1
y ||= 0; // 1
      
      





El operador de asignación lógica nullish (x ?? = y) realiza una operación de asignación solo si x es NULL ( nulo o indefinido ).



x ?? = y es equivalente ax ?? (x = y) , y no equivalente a x = x ?? en .



let x = undefined;
let y = '';

x ??= null; // null
x ??= 'a value'; // "a value"
y ??= undefined; // ""
y ??= null; // ""
      
      





Otros cambios



Además del modo de lanzamiento en el rechazo de promesas no manejadas y las nuevas características del lenguaje V8 8.6, Node.js 15 tiene los siguientes cambios:



NPM 7 : muchos cambios, incluida la instalación automática de dependencias entre pares, mejoras en los paquetes y archivos yarn.lock, compatibilidad con el espacio de trabajo , etc. Todo esto se describe en este artículo por referencia .



QUIC : Soporte experimental para la capa de transporte UDP, que es el protocolo principal para HTTP / 3. QUIC incluye seguridad incorporada con TLS 1.3, control de flujo, corrección de errores, migración de conexiones y multiplexación.



N-API Versión 7: API para crear complementos personalizados. Es independiente del tiempo de ejecución de JavaScript subyacente y se admite como parte de Node.js.



Mejora de la API de almacenamiento local asíncrono : brinda la capacidad de un registro y análisis de características más modernos para aplicaciones a gran escala.



Conclusión



La nueva versión de Node.js 15 tiene una gran cantidad de nuevas características y mejoras, incluidas algunas bastante significativas.



Prueba la nueva versión y prepárate para actualizar proyectos.



¡Gracias por la atención! Espero que el artículo te haya sido útil.



All Articles