Los lenguajes dinámicos son herramientas útiles. La creación de secuencias de comandos permite a los usuarios vincular rápida y sucintamente sistemas complejos y expresar ideas sin preocuparse por detalles como la administración de memoria o los sistemas de compilación.

En los últimos años, los lenguajes de programación como Rust and Go han facilitado mucho la producción de sofisticados códigos de máquina nativos.

Estos proyectos son desarrollos increíblemente importantes en infraestructura informática. Sin embargo, afirmamos que todavía es importante tener un entorno de secuencias de comandos potente que pueda abordar una amplia gama de dominios problemáticos.

JavaScript es el lenguaje dinámico más utilizado, opera en todos los dispositivos con un navegador web. Un gran número de programadores tienen fluidez en JavaScript y se ha hecho un gran esfuerzo para optimizar su ejecución.

A través de organizaciones de estándares como ECMA International, el lenguaje se ha mejorado cuidadosa y continuamente. Creemos que JavaScript es la opción natural para las herramientas de lenguaje dinámico; ya sea en un entorno de navegador o como procesos independientes.

Nuestra empresa original en esta área, Node.js, demostró ser una plataforma de software muy exitosa. Las personas lo han encontrado útil para construir herramientas de desarrollo web, construir servidores web independientes y para una miríada de otros casos de uso.

Nodo, sin embargo, fue diseñado en 2009 cuando JavaScript era un lenguaje muy diferente. Por necesidad, Node tuvo que inventar conceptos que luego fueron adoptados por las organizaciones de estándares y agregados al lenguaje de manera diferente. En la presentación Design Mistakes in Node , esto se discute con más detalle. Debido a la gran cantidad de usuarios que tiene Node, es difícil y lento evolucionar el sistema.

Con el cambio del lenguaje JavaScript y las nuevas incorporaciones como TypeScript, la creación de proyectos Node puede convertirse en un esfuerzo arduo, que implica la gestión de sistemas de compilación y otras herramientas pesadas que le quitan la diversión a las secuencias de comandos de lenguaje dinámico.

Además, el mecanismo para vincular a bibliotecas externas está fundamentalmente centralizado a través del repositorio de NPM, que no está en línea con los ideales de la web.

Creemos que el panorama de JavaScript y la infraestructura de software circundante ha cambiado lo suficiente como para que valiera la pena simplificarlo. Buscamos un entorno de scripting divertido y productivo que se pueda utilizar para una amplia gama de tareas.

Un navegador web para scripts de línea de comandos

Deno es un nuevo tiempo de ejecución para ejecutar JavaScript y TypeScript fuera del navegador web.

Deno intenta proporcionar una herramienta independiente para crear rápidamente secuencias de comandos de funcionalidad compleja.

Deno es (y siempre será) un único archivo ejecutable. Al igual que un navegador web, sabe cómo obtener código externo. En Deno, un solo archivo puede definir un comportamiento complejo arbitrario sin ninguna otra herramienta.

import { serve } from "https://deno.land/[email protected]/http/server.ts";

for await (const req of serve({ port: 8000 })) {
  req.respond({ body: "Hello World\n" });
}

Aquí se agrega un módulo de servidor HTTP completo como una dependencia en una sola línea. No hay archivos de configuración adicionales, no hay instalación que hacer de antemano, solo deno run example.js.

También como los navegadores, el código se ejecuta en un entorno seguro por defecto. Las secuencias de comandos no pueden acceder al disco duro, abrir conexiones de red o realizar otras acciones potencialmente maliciosas sin permiso.

El navegador proporciona API para acceder a cámaras y micrófonos, pero los usuarios primero deben dar permiso. Deno proporciona un comportamiento análogo en la terminal. El ejemplo anterior fallará a menos que --allow-net se proporcione el indicador de línea de comando.

Deno tiene cuidado de no desviarse de las API JavaScript estandarizadas del navegador. Por supuesto, no todas las API de navegador son relevantes para Deno, pero donde están, Deno no se desvía del estándar.

Deno más TypeScript de primera clase

Queremos que Deno sea aplicable a una amplia gama de dominios problemáticos: desde pequeños scripts de una línea hasta complejas lógicas comerciales del lado del servidor.

A medida que los programas se vuelven más complejos, tener alguna forma de verificación de tipo se vuelve cada vez más importante. TypeScript es una extensión del lenguaje JavaScript que permite a los usuarios proporcionar opcionalmente información de tipo.

Deno admite TypeScript sin herramientas adicionales. El tiempo de ejecución está diseñado con TypeScript en mente. El deno typescomando proporciona declaraciones de tipo para todo lo proporcionado por Deno. Todos los módulos estándar de Deno están escritos en TypeScript.

Objeto Promises y Deno

Node fue diseñado antes de que JavaScript tuviera el concepto de Promesas o async / wait. La contraparte de las promesas de Node fue EventEmitter, que se basa en API importantes, a saber, sockets y HTTP. Dejando de lado los beneficios ergonómicos de async / wait, el patrón EventEmitter tiene un problema con la contrapresión.

Tome un socket TCP, por ejemplo.

El socket emitiría eventos de “datos” cuando recibiera paquetes entrantes. Estas devoluciones de llamada de “datos” se emitirían sin restricciones, inundando el proceso con eventos. Debido a que Node continúa recibiendo nuevos eventos de datos, el socket TCP subyacente no tiene una contrapresión adecuada, el remitente remoto no tiene idea de que el servidor está sobrecargado y continúa enviando datos.

Para mitigar este problema, se agregó un método pause(). Esto podría resolver el problema, pero requería código adicional; y dado que el problema de la inundación solo se presenta cuando el proceso está muy ocupado, muchos programas Node pueden inundarse de datos. El resultado es un sistema con mala latencia de cola.

En Deno, los sockets siguen siendo asíncronos, pero recibir nuevos datos requiere que los usuarios lo hagan explícitamente read(). No es necesaria una semántica de pausa adicional para estructurar adecuadamente un socket receptor. Esto no es exclusivo de los sockets TCP. La capa de enlace de nivel más bajo para el sistema está fundamentalmente vinculada a las promesas: llamamos a estos enlaces “ops”. Todas las devoluciones de llamada en Deno de una forma u otra surgen de promesas.

Rust tiene su propia abstracción prometedora, llamada Futures. A través de la abstracción “op”, Deno facilita la vinculación de las API basadas en el futuro de Rust a las promesas de JavaScript.

🛒 Los Mejores Chollos de Amazon, ¡Agrégalos a tu Lista de Deseos!

API de Rust de Deno

El componente principal que enviamos es la interfaz de línea de comandos (CLI) de Deno. La CLI es lo que es la versión 1.0 hoy. Pero Deno no es un programa monolítico, sino que está diseñado como una colección de cajas Rust para permitir la integración en diferentes capas.

La caja deno_core es una versión muy básica de Deno. No tiene dependencias en TypeScript ni en Tokio . Simplemente proporciona nuestra infraestructura de operaciones y recursos. Es decir, proporciona una forma organizada de vincular los futuros de Rust a las promesas de JavaScript. La CLI, por supuesto, está construida completamente sobre deno_core.

La caja rusty_v8 proporciona enlaces Rust de alta calidad a la API C ++ de V8. La API intenta hacer coincidir la API original de C ++ lo más cerca posible. Es un enlace de costo cero: los objetos que están expuestos en Rust son exactamente el objeto que manipulas en C ++. (Los intentos anteriores en los enlaces Rust V8 forzaron el uso de controladores persistentes, por ejemplo).

La caja proporciona binarios que se crean en Github Actions CI, pero también permite a los usuarios compilar V8 desde cero y ajustar sus muchas configuraciones de construcción. Todo el código fuente V8 se distribuye en la caja misma. Finalmente, rusty_v8 intenta ser una interfaz segura. Todavía no es 100% seguro, pero nos estamos acercando. Poder interactuar con una VM tan compleja como V8 de manera segura es bastante sorprendente y nos ha permitido descubrir muchos errores difíciles en Deno.

Estabilidad de Deno

Prometemos mantener una API estable en Deno. Deno tiene muchas interfaces y componentes, por lo que es importante ser transparente sobre lo que queremos decir con “estable”. Las API de JavaScript que hemos inventado para interactuar con el sistema operativo se encuentran dentro del espacio de nombres “Deno” (por ejemplo Deno.open()). Estos han sido cuidadosamente examinados y no haremos cambios hacia atrás incompatibles con ellos.

Toda la funcionalidad que aún no está lista para la estabilización se ha ocultado detrás del –unstableindicador de línea de comando. Puede ver la documentación de las interfaces inestables aquí . En versiones posteriores, algunas de estas API también se estabilizarán.

En el espacio de nombres global encontrará todo tipo de otros objetos (por ejemplo, setTimeout() y fetch()). Hemos tratado muy duro para mantener estas interfaces idénticas a las del navegador; pero emitiremos correcciones si descubrimos incompatibilidades inadvertidas. Los estándares del navegador definen estas interfaces, no nosotros. Las correcciones emitidas por nosotros son correcciones de errores, no cambios en la interfaz. Si hay una incompatibilidad con una API estándar del navegador, esa incompatibilidad puede corregirse antes de una versión principal.

Deno también tiene muchas API de Rust, a saber, las cajas deno_core y rusty_v8. Ninguna de estas API está en 1.0 todavía. Continuaremos iterando sobre ellos.

Limitaciones de Deno

Es importante comprender que Deno no es una bifurcación de Node, es una implementación completamente nueva. Deno ha estado en desarrollo durante solo dos años, mientras que Node ha estado en desarrollo durante más de una década. Dada la cantidad de interés en Deno, esperamos que continúe evolucionando y madurando.

Para algunas aplicaciones, Deno puede ser una buena opción hoy, para otras todavía no. Dependerá de los requisitos. Queremos ser transparentes acerca de estas limitaciones para ayudar a las personas a tomar decisiones informadas cuando consideren usar Deno.

Compatibilidad de Deno

Desafortunadamente, muchos usuarios encontrarán una frustrante falta de compatibilidad con las herramientas JavaScript existentes. Deno no es compatible, en general, con los paquetes Node (NPM). Se está creando una capa de compatibilidad naciente en https://deno.land/std/node/ pero está lejos de completarse.

Aunque Deno ha adoptado un enfoque de línea dura para simplificar el sistema de módulos, en última instancia, Deno y Node son sistemas bastante similares con objetivos similares. Con el tiempo, esperamos que Deno pueda ejecutar más y más programas Node listos para usar.

🛒 Los Mejores Chollos de Amazon, ¡Agrégalos a tu Lista de Deseos!

Rendimiento del servidor HTTP de Deno

Seguimos continuamente el rendimiento del servidor HTTP de Deno. Un servidor HTTP Deno-hello-world realiza aproximadamente 25k solicitudes por segundo con una latencia máxima de 1.3 milisegundos. Un programa Node comparable realiza 34k solicitudes por segundo con una latencia máxima bastante errática entre 2 y 300 milisegundos.

El servidor HTTP de Deno se implementa en TypeScript sobre los sockets TCP nativos. El servidor HTTP de Node está escrito en C y expuesto como enlaces de alto nivel a JavaScript. Hemos resistido la necesidad de agregar enlaces de servidores HTTP nativos a Deno, porque queremos optimizar la capa de socket TCP y, en general, la interfaz operativa.

Deno es un servidor asíncrono adecuado y 25k solicitudes por segundo son suficientes para la mayoría de los propósitos. (Si no lo es, probablemente JavaScript no sea la mejor opción). Además, esperamos que Deno exhiba generalmente una mejor latencia de cola debido al uso ubicuo de las promesas (discutido anteriormente). Dicho todo esto, creemos que hay más victorias de rendimiento en el sistema, y ​​esperamos lograrlo en futuras versiones.

Los cuellos de botella TSC en Deno

Internamente, Deno utiliza el compilador TypeScript de Microsoft para verificar los tipos y producir JavaScript. En comparación con el tiempo que tarda V8 en analizar JavaScript, es muy lento. Al principio del proyecto, esperábamos que las “instantáneas V8” proporcionaran mejoras significativas aquí. Las instantáneas ciertamente han ayudado, pero todavía es insatisfactoriamente lento. Ciertamente creemos que hay mejoras que se pueden hacer aquí además del compilador TypeScript existente, pero tenemos claro que, en última instancia, la verificación de tipo debe implementarse en Rust. Esta será una empresa masiva y no sucederá en el corto plazo; pero proporcionaría mejoras en el orden de magnitud del rendimiento en una ruta crítica experimentada por los desarrolladores. TSC debe ser portado a Rust. Si está interesado en colaborar en este problema, póngase en contacto.

Los complementos / extensiones de Deno

Tenemos un nuevo sistema de complementos para extender el tiempo de ejecución de Deno con operaciones personalizadas. Sin embargo, esta interfaz todavía está en desarrollo y se ha marcado como inestable. Por lo tanto, acceder a sistemas nativos más allá de lo que proporciona Deno es difícil.

▶ Probar Deno

🛒 Los Mejores Chollos de Amazon, ¡Agrégalos a tu Lista de Deseos!

El futuro sustituto de NodeJS: Un tiempo de ejecución seguro de JavaScript y TypeScript.