JS Fest 2019. Ryan Dahl. Deno, a new way to JavaScript

J
Deno
Ryan Dahl
2019.04.04
Kiev, Ukraine
Disclaimer
This talk is aimed at experienced enthusiasts
If this isn't you: Don't Panic
Ignore this talk - use Node. Node isn't going anywhere!
Deno is a new command-line runtime
for executing JavaScript and TypeScript
Primarily it is built on top of:
● V8
● Rust
● Tokio (event loop)
● TypeScript
But why!? Isn't this exactly what Node does?
JavaScript (both the language itself and the ecosystem around it) has changed
significantly since Node was designed in 2009. Notably:
● Promises / Async / Await
● ES Modules
● Typed Arrays
Node has problems:
● A poorly designed module system, with centralized distribution.
● Lots of legacy APIs that must be supported.
● Security.
(These problems aren't unique to Node. Python and Ruby suffer similarly)
I want a fun and productive system for scripting.
A good scripting platform is too useful of a tool to
shrug and accept the status quo.
I find neither Node nor
Python nor Ruby nor any
other dynamic language
platform satisfactory.
Deno attempts to correct design mistakes in Node by
radically breaking compatibility
● ES modules are the one and only module system
○ HTTP URLs are used to link to third party code
○ Deno has the ability to fetch resources itself, so it is its own package manager.
● Deno is secure by default
○ Users must give extra permission to access the disk, network, or otherwise do privileged
operations.
● Deno maintains browser compatibility
○ The subset of Deno programs which are written completely in JavaScript and do not use the
global Deno object should also run in a modern web browser without change.
Example 1
deno -h
REPL
deno --types
cat program
Example 2
location.href
import.meta
Example 3
echo_server
http server
file_server
Example 4
testing
Deno is (kind of) like an OS
Linux
Processes
Syscalls
File descriptors (fd)
Scheduler
Userland: libc++ / glib / boost
/proc/$$/stat
man pages
Deno
Web Workers
Ops
Resource ids (rid)
Tokio
deno_std
deno.metrics()
deno --types
V8 (C++)
Deno (Rust)
deno::Isolate (Rust)
Uint8Array
Internal Design (VERY VERY simplified)
Deno.core.send()
Deno.core.recv()
JS
V8 (C++)
libdeno (C++)
deno process (Rust)
deno_recv_cb
deno_send
deno::Isolate (Rust)
Tokio thread pool (Rust)
deno_buf
"ops"
Resources (Rust)
stdio
TCP socket
child process
... etc
Internal Design (Very Simplified)
thread1 thread2 thread3 thread4
Deno.core.send()
Deno.core.recv()
//js (JS)
Embedding Deno
https://crates.io/crates/deno
Deno is released as a standalone executable, but it's also embeddable.
There are many situations where one might want to execute a bit of JavaScript,
but shelling out to Node (or Deno) is too insecure, complex, or generally
inappropriate:
○ Databases often use a JavaScript for Map Reduce functions
○ Serverless products like Lambda@Edge or Cloudflare Workers
Using raw V8 is difficult
Embedding Deno
https://crates.io/crates/deno
Essentially all you need to implement is this callback:
fn dispatch(
&mut self,
control: &[u8],
zero_copy_buf: deno_buf
) -> (bool, Box<Op>)
(rust)
deno_std (Standard Modules)
Deno core is kept as minimal as possible.
However it's useful to have high quality standard modules.
https://github.com/denoland/deno_std
● This partially addresses the "dependency hell" problem by not having external
deps.
● All code is reviewed by me (at least superficially)
● Is tagged with each Deno release: https://deno.land/std@v0.3.2/
Deno Performance
We continuously run benchmarks, to ensure our performance goes in the right
direction over time. Startup time is shown below (3x faster than Node)
Deno I/O Performance: improving but not fast yet
Deno I/O Performance: improving but not fast yet
Deno CLI TCP
Deno Core TCP
Node TCP
Deno I/O Performance: improving but not fast yet
Perf gap between
deno_core and CLI
Will be closed soon.
Roadmap: Aiming for 1.0 by end of summer
Soon:
● I/O performance issues must be fixed (mentioned earlier)
● Parallelize code loading pipeline (initialization progress bar)
● TLS / SSL
● Lock file for external modules
● Expose snapshotting to deno_core
● Debugger
Eventually:
● WebCrypto
● File system events
● WebGL
And others!
Deno is an open collaboration of many people.
Contributions welcome!
Thanks!
Comments? Questions? Concerns?
ry@tinyclouds.org
JS Fest 2019. Ryan Dahl. Deno, a new way to JavaScript
ES Modules map bijectively onto JavaScript files
This is a wonderful simplification over languages where "modules" and "source
code files" are not the same. It is one less concept for users to grok.
Files map bijectively onto URLs. Therefore modules map to URLs.
ES Module <=> JS File <=> JS URL
This is a very simple and file-centric programming model.
URL <=> source code <=> Module
For this reason, we've chosen to deviate from the convention of importing
TypeScript files without file extensions.
We require that module specifies that are paths to actual files:
import { red } from "https://deno.land/std/colors/mod.ts";
This maintains the bijection, and if it sticks, it will provide a simpler conceptual
basis for new users.
Please consider adopting this convention for TS code outside of Deno.
UNIX is also a very file-centric programming model
but over data rather than source files.
Inspired by this, Deno has the following design constraint:
1. Users should be able to allocate a Typed Array in JS, and tell the kernel to
read(2) into it.
2. Users should be able to pass a locally allocated Typed Array to the kernel for
a write(2) syscall without an internal memcpy happening.
Colloquially this is known as "zero-copy"
UNIX inspired I/O
Traditional UNIX programs use blocking reads and writes to process data:
char buf[64];
size_t n;
for (;;) {
n = read(STDIN_FILENO, buf, 64);
if (n <= 0) break;
n = write(STDOUT_FILENO, buf, n);
if (n <= 0) break;
}
UNIX inspired I/O
Traditional UNIX programs use blocking reads and writes to process data:
char buf[64];
size_t n;
for (;;) {
n = read(STDIN_FILENO, buf, 64);
if (n <= 0) break;
n = write(STDOUT_FILENO, buf, n);
if (n <= 0) break;
}
Zero-copy.
Fixed buf allocation.
Thus: efficient
UNIX inspired I/O
Traditional UNIX programs use blocking reads and writes to process data:
char buf[64];
size_t n;
for (;;) {
n = read(STDIN_FILENO, buf, 64);
if (n <= 0) break;
n = write(STDOUT_FILENO, buf, n);
if (n <= 0) break;
}
Different data streams
abstracted as a FD
Thus: composable
Zero-copy.
Fixed buf allocation.
Thus: efficient
UNIX inspired I/O
Traditional UNIX programs use blocking reads and writes to process data:
char buf[64];
size_t n;
for (;;) {
n = read(STDIN_FILENO, buf, 64);
if (n <= 0) break;
n = write(STDOUT_FILENO, buf, n);
if (n <= 0) break;
}
Different data streams
abstracted as a FD
Thus: composable
Does not read more
than it can handle.
Thus: back-pressure
Zero-copy.
Fixed buf allocation.
Thus: efficient
Go's Reader/Writer is the modern ideal of UNIX
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
The interfaces model the
read(2) write(2)
syscalls without relying on
FDs (which imply
expensive syscalls).
Not every type of data
stream needs a FD
E.G. gzip.
Expressing Reader/Writer in TypeScript
interface Reader {
read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>;
}
interface Writer {
write(p: Uint8Array): Promise<number>;
}
Expressing Reader/Writer in TypeScript
interface Reader {
read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>;
}
interface Writer {
write(p: Uint8Array): Promise<number>;
}
ArrayBuffers allow raw
memory access
Thus: efficient
Expressing Reader/Writer in TypeScript
interface Reader {
read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>;
}
interface Writer {
write(p: Uint8Array): Promise<number>;
}
TS interfaces allow
abstracting different
data streams
Thus: composable
ArrayBuffers allow raw
memory access
Thus: efficient
Expressing Reader/Writer in TypeScript
interface Reader {
read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>;
}
interface Writer {
write(p: Uint8Array): Promise<number>;
}
TS interfaces allow
abstracting different
data streams
Thus: composable
Async/Await allows
ergonomic sequencing
Thus: back-pressure
ArrayBuffers allow raw
memory access
Thus: efficient
Building a runtime around Reader/Writer allows us
to port other concepts, tests, and documentation
from Go.
Good ideas should be reused - and there are many of them in Go.
Examples:
Buffer ported from bytes.Buffer
copy() ported from io.Copy()
BufReader() ported from bufio.Reader
1 of 37

More Related Content

What's hot(20)

GraalVMGraalVM
GraalVM
NexThoughts Technologies921 views
OpenID Connect ExplainedOpenID Connect Explained
OpenID Connect Explained
Vladimir Dzhuvinov11.3K views
Java 9 FeaturesJava 9 Features
Java 9 Features
NexThoughts Technologies774 views
Web designing unit 4Web designing unit 4
Web designing unit 4
SURBHI SAROHA135 views
Node.js  ExpressNode.js  Express
Node.js Express
Eyal Vardi4.8K views
Introduction to Apache CamelIntroduction to Apache Camel
Introduction to Apache Camel
Claus Ibsen5.6K views
Composer 經典食譜Composer 經典食譜
Composer 經典食譜
Shengyou Fan1.6K views
Git & GitHub for BeginnersGit & GitHub for Beginners
Git & GitHub for Beginners
Sébastien Saunier14.5K views
jQuery AjaxjQuery Ajax
jQuery Ajax
Anand Kumar Rajana3.8K views
CMSでのXSS to RCEを触ってみたCMSでのXSS to RCEを触ってみた
CMSでのXSS to RCEを触ってみた
adachi tomohiro563 views
Progressive Web AppProgressive Web App
Progressive Web App
SaleemMalik522.8K views
Documenting your REST API with Swagger - JOIN 2014Documenting your REST API with Swagger - JOIN 2014
Documenting your REST API with Swagger - JOIN 2014
JWORKS powered by Ordina830 views
Node jsNode js
Node js
Fatih Şimşek1.6K views
AEM Rich Text Editor (RTE) Deep DiveAEM Rich Text Editor (RTE) Deep Dive
AEM Rich Text Editor (RTE) Deep Dive
Hanish Bansal2.3K views
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
Taku Miyakawa74.2K views

Similar to JS Fest 2019. Ryan Dahl. Deno, a new way to JavaScript(20)

More from JSFestUA(20)

Recently uploaded(20)

Lecture: Open InnovationLecture: Open Innovation
Lecture: Open Innovation
Michal Hron94 views
Azure DevOps Pipeline setup for Mule APIs #36Azure DevOps Pipeline setup for Mule APIs #36
Azure DevOps Pipeline setup for Mule APIs #36
MysoreMuleSoftMeetup84 views
2022 CAPE Merit List 2023 2022 CAPE Merit List 2023
2022 CAPE Merit List 2023
Caribbean Examinations Council3.5K views
Scope of Biochemistry.pptxScope of Biochemistry.pptx
Scope of Biochemistry.pptx
shoba shoba119 views
Chemistry of sex hormones.pptxChemistry of sex hormones.pptx
Chemistry of sex hormones.pptx
RAJ K. MAURYA107 views
Narration  ppt.pptxNarration  ppt.pptx
Narration ppt.pptx
TARIQ KHAN76 views
Nico Baumbach IMR Media ComponentNico Baumbach IMR Media Component
Nico Baumbach IMR Media Component
InMediaRes1368 views
STERILITY TEST.pptxSTERILITY TEST.pptx
STERILITY TEST.pptx
Anupkumar Sharma107 views
AI Tools for Business and StartupsAI Tools for Business and Startups
AI Tools for Business and Startups
Svetlin Nakov74 views
Industry4wrd.pptxIndustry4wrd.pptx
Industry4wrd.pptx
BC Chew157 views
Material del tarjetero LEES Travesías.docxMaterial del tarjetero LEES Travesías.docx
Material del tarjetero LEES Travesías.docx
Norberto Millán Muñoz60 views
Plastic waste.pdfPlastic waste.pdf
Plastic waste.pdf
alqaseedae94 views
231112 (WR) v1  ChatGPT OEB 2023.pdf231112 (WR) v1  ChatGPT OEB 2023.pdf
231112 (WR) v1 ChatGPT OEB 2023.pdf
WilfredRubens.com118 views
Sociology KS5Sociology KS5
Sociology KS5
WestHatch52 views

JS Fest 2019. Ryan Dahl. Deno, a new way to JavaScript

  • 2. Disclaimer This talk is aimed at experienced enthusiasts If this isn't you: Don't Panic Ignore this talk - use Node. Node isn't going anywhere!
  • 3. Deno is a new command-line runtime for executing JavaScript and TypeScript Primarily it is built on top of: ● V8 ● Rust ● Tokio (event loop) ● TypeScript
  • 4. But why!? Isn't this exactly what Node does? JavaScript (both the language itself and the ecosystem around it) has changed significantly since Node was designed in 2009. Notably: ● Promises / Async / Await ● ES Modules ● Typed Arrays Node has problems: ● A poorly designed module system, with centralized distribution. ● Lots of legacy APIs that must be supported. ● Security. (These problems aren't unique to Node. Python and Ruby suffer similarly)
  • 5. I want a fun and productive system for scripting. A good scripting platform is too useful of a tool to shrug and accept the status quo. I find neither Node nor Python nor Ruby nor any other dynamic language platform satisfactory.
  • 6. Deno attempts to correct design mistakes in Node by radically breaking compatibility ● ES modules are the one and only module system ○ HTTP URLs are used to link to third party code ○ Deno has the ability to fetch resources itself, so it is its own package manager. ● Deno is secure by default ○ Users must give extra permission to access the disk, network, or otherwise do privileged operations. ● Deno maintains browser compatibility ○ The subset of Deno programs which are written completely in JavaScript and do not use the global Deno object should also run in a modern web browser without change.
  • 7. Example 1 deno -h REPL deno --types cat program
  • 11. Deno is (kind of) like an OS Linux Processes Syscalls File descriptors (fd) Scheduler Userland: libc++ / glib / boost /proc/$$/stat man pages Deno Web Workers Ops Resource ids (rid) Tokio deno_std deno.metrics() deno --types
  • 12. V8 (C++) Deno (Rust) deno::Isolate (Rust) Uint8Array Internal Design (VERY VERY simplified) Deno.core.send() Deno.core.recv() JS
  • 13. V8 (C++) libdeno (C++) deno process (Rust) deno_recv_cb deno_send deno::Isolate (Rust) Tokio thread pool (Rust) deno_buf "ops" Resources (Rust) stdio TCP socket child process ... etc Internal Design (Very Simplified) thread1 thread2 thread3 thread4 Deno.core.send() Deno.core.recv() //js (JS)
  • 14. Embedding Deno https://crates.io/crates/deno Deno is released as a standalone executable, but it's also embeddable. There are many situations where one might want to execute a bit of JavaScript, but shelling out to Node (or Deno) is too insecure, complex, or generally inappropriate: ○ Databases often use a JavaScript for Map Reduce functions ○ Serverless products like Lambda@Edge or Cloudflare Workers Using raw V8 is difficult
  • 15. Embedding Deno https://crates.io/crates/deno Essentially all you need to implement is this callback: fn dispatch( &mut self, control: &[u8], zero_copy_buf: deno_buf ) -> (bool, Box<Op>) (rust)
  • 16. deno_std (Standard Modules) Deno core is kept as minimal as possible. However it's useful to have high quality standard modules. https://github.com/denoland/deno_std ● This partially addresses the "dependency hell" problem by not having external deps. ● All code is reviewed by me (at least superficially) ● Is tagged with each Deno release: https://deno.land/std@v0.3.2/
  • 17. Deno Performance We continuously run benchmarks, to ensure our performance goes in the right direction over time. Startup time is shown below (3x faster than Node)
  • 18. Deno I/O Performance: improving but not fast yet
  • 19. Deno I/O Performance: improving but not fast yet Deno CLI TCP Deno Core TCP Node TCP
  • 20. Deno I/O Performance: improving but not fast yet Perf gap between deno_core and CLI Will be closed soon.
  • 21. Roadmap: Aiming for 1.0 by end of summer Soon: ● I/O performance issues must be fixed (mentioned earlier) ● Parallelize code loading pipeline (initialization progress bar) ● TLS / SSL ● Lock file for external modules ● Expose snapshotting to deno_core ● Debugger Eventually: ● WebCrypto ● File system events ● WebGL
  • 22. And others! Deno is an open collaboration of many people. Contributions welcome!
  • 25. ES Modules map bijectively onto JavaScript files This is a wonderful simplification over languages where "modules" and "source code files" are not the same. It is one less concept for users to grok. Files map bijectively onto URLs. Therefore modules map to URLs. ES Module <=> JS File <=> JS URL This is a very simple and file-centric programming model.
  • 26. URL <=> source code <=> Module For this reason, we've chosen to deviate from the convention of importing TypeScript files without file extensions. We require that module specifies that are paths to actual files: import { red } from "https://deno.land/std/colors/mod.ts"; This maintains the bijection, and if it sticks, it will provide a simpler conceptual basis for new users. Please consider adopting this convention for TS code outside of Deno.
  • 27. UNIX is also a very file-centric programming model but over data rather than source files. Inspired by this, Deno has the following design constraint: 1. Users should be able to allocate a Typed Array in JS, and tell the kernel to read(2) into it. 2. Users should be able to pass a locally allocated Typed Array to the kernel for a write(2) syscall without an internal memcpy happening. Colloquially this is known as "zero-copy"
  • 28. UNIX inspired I/O Traditional UNIX programs use blocking reads and writes to process data: char buf[64]; size_t n; for (;;) { n = read(STDIN_FILENO, buf, 64); if (n <= 0) break; n = write(STDOUT_FILENO, buf, n); if (n <= 0) break; }
  • 29. UNIX inspired I/O Traditional UNIX programs use blocking reads and writes to process data: char buf[64]; size_t n; for (;;) { n = read(STDIN_FILENO, buf, 64); if (n <= 0) break; n = write(STDOUT_FILENO, buf, n); if (n <= 0) break; } Zero-copy. Fixed buf allocation. Thus: efficient
  • 30. UNIX inspired I/O Traditional UNIX programs use blocking reads and writes to process data: char buf[64]; size_t n; for (;;) { n = read(STDIN_FILENO, buf, 64); if (n <= 0) break; n = write(STDOUT_FILENO, buf, n); if (n <= 0) break; } Different data streams abstracted as a FD Thus: composable Zero-copy. Fixed buf allocation. Thus: efficient
  • 31. UNIX inspired I/O Traditional UNIX programs use blocking reads and writes to process data: char buf[64]; size_t n; for (;;) { n = read(STDIN_FILENO, buf, 64); if (n <= 0) break; n = write(STDOUT_FILENO, buf, n); if (n <= 0) break; } Different data streams abstracted as a FD Thus: composable Does not read more than it can handle. Thus: back-pressure Zero-copy. Fixed buf allocation. Thus: efficient
  • 32. Go's Reader/Writer is the modern ideal of UNIX type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } The interfaces model the read(2) write(2) syscalls without relying on FDs (which imply expensive syscalls). Not every type of data stream needs a FD E.G. gzip.
  • 33. Expressing Reader/Writer in TypeScript interface Reader { read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>; } interface Writer { write(p: Uint8Array): Promise<number>; }
  • 34. Expressing Reader/Writer in TypeScript interface Reader { read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>; } interface Writer { write(p: Uint8Array): Promise<number>; } ArrayBuffers allow raw memory access Thus: efficient
  • 35. Expressing Reader/Writer in TypeScript interface Reader { read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>; } interface Writer { write(p: Uint8Array): Promise<number>; } TS interfaces allow abstracting different data streams Thus: composable ArrayBuffers allow raw memory access Thus: efficient
  • 36. Expressing Reader/Writer in TypeScript interface Reader { read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>; } interface Writer { write(p: Uint8Array): Promise<number>; } TS interfaces allow abstracting different data streams Thus: composable Async/Await allows ergonomic sequencing Thus: back-pressure ArrayBuffers allow raw memory access Thus: efficient
  • 37. Building a runtime around Reader/Writer allows us to port other concepts, tests, and documentation from Go. Good ideas should be reused - and there are many of them in Go. Examples: Buffer ported from bytes.Buffer copy() ported from io.Copy() BufReader() ported from bufio.Reader