今天看啥  ›  专栏  ›  鲨叔

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

鲨叔  · 掘金  ·  · 2019-04-09 11:08
  1. Deno Ryan Dahl 2019.04.04 Kiev, Ukraine
  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
  8. Example 2 location.href import.meta
  9. Example 3 echo_server http server file_server
  10. Example 4 testing
  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!
  23. Thanks! Comments? Questions? Concerns? ry@tinyclouds.org
  24. 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.
  25. 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.
  26. 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"
  27. 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; }
  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; } Zero-copy. Fixed buf allocation. Thus: efficient
  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; } Different data streams abstracted as a FD Thus: composable 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 Does not read more than it can handle. Thus: back-pressure Zero-copy. Fixed buf allocation. Thus: efficient
  31. 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.
  32. Expressing Reader/Writer in TypeScript interface Reader { read(p: Uint8Array): Promise<{ nread: number, eof: boolean }>; } interface Writer { write(p: Uint8Array): Promise<number>; }
  33. 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
  34. 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
  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 Async/Await allows ergonomic sequencing Thus: back-pressure ArrayBuffers allow raw memory access Thus: efficient
  36. 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



原文地址:访问原文地址
快照地址: 访问文章快照