全新的JavaScript runtime —— Deno 初体验

简介: 全新的JavaScript runtime —— Deno 初体验

640.jpg

写在前面


2020年5月13日,Deno终于正式发布了。Deno是基于V8 JavaScript引擎和Rust编程语言的JavaScript和TypeScript运行时。它是由Node.js之父Ryan Dahl创建的,专注于安全性和生产力。


为什么会有Deno


已经有了Node.js,为什么还要搞一个Deno呢?按Ryan Dahl在2018年的一个演讲,他在设计Node.js的时候,犯了几个"错误"(演讲PPT我之前收集过,在公众号回复 前端学习 即可自行获取)。这几个"错误"是:


  1. 没有坚持使用Promise。
  2. 没有足够的安全性。
  3. 构建系统没有从GYP(node-gyp)切到GN。
  4. 继续使用GYP,没有提供Foreign Function Interface (FFI)的模式。
  5. package.json(依赖了npm)。
  6. 在任何地方都可以require('module')。
  7. package.json提供了错误的模块概念。
  8. node_modules黑洞。
  9. require('module') 没有加上扩展名'.js'。
  10. 默认加载index.js。


于是,Ryan Dahl决定开发一个新的JavaScript运行时。2年多后,Deno v1.0发布了。官网地址:

https://deno.land/


Deno初体验


赶紧来体验一下Deno。


安装


macOS下直接curl即可:curl -fsSL https://deno.land/x/install/install.sh | sh


更多安装方式,请移步官网


下载完成后,将deno加入系统环境变量。首先


> vi ~/.bash_profile


接着,加入以下两行:


export DENO_INSTALL="/Users/pankeyu/.deno"export PATH="$DENO_INSTALL/bin:$PATH"


最后,执行:


source ~/.bash_profile


然后,就可以在命令行愉快的执行deno了:

640.png


命令行


deno命令行的用法和node差不太多。

640.png



想要执行脚本,直接deno run ${script}即可。这里的script,也可以是一个线上文件。


直接执行代码,可以 deno eval "console.log(30933 + 404)"


deno支持以下命令:


bundle         Bundle module and dependencies into single filecache          Cache the dependenciescompletions    Generate shell completionsdoc            Show documentation for a moduleeval           Eval scriptfmt            Format source files help           Prints this message or the help of the given subcommand(s)info           Show info about cache or info related to source fileinstall        Install script as an executablerepl           Read Eval Print Looprun            Run a program given a filename or url to the moduletest           Run tests types          Print runtime TypeScript declarationsupgrade        Upgrade deno executable to given version


更多信息,可以使用deno help查看。


从上面的bundle、test、fmt命令我们可以看出来:deno原生支持打包,测试,格式化


使用deno创建一个http server


我们使用官方的例子:


// server.tsimport { serve } from "https://deno.land/std@0.50.0/http/server.ts";const s = serve({ port: 8000 });console.log("http://localhost:8000/");for await (const req of s) {  req.respond({ body: "Hello World\n" });}


执行deno server.ts,命令行输出:

640.png


可以看到,直接报错了。这是deno的安全机制,需要加上--allow-net这个参数,才可以访问网络。


执行deno --allow-net server.ts,命令行输出如下:


> deno --allow-net server.tsCompile file:///Users/pankeyu/Desktop/server.tsDownload https://deno.land/std@0.50.0/http/server.tsDownload https://deno.land/std@0.50.0/encoding/utf8.tsDownload https://deno.land/std@0.50.0/io/bufio.tsDownload https://deno.land/std@0.50.0/testing/asserts.tsDownload https://deno.land/std@0.50.0/async/mod.tsDownload https://deno.land/std@0.50.0/http/_io.tsDownload https://deno.land/std@0.50.0/io/util.tsDownload https://deno.land/std@0.50.0/path/mod.tsDownload https://deno.land/std@0.50.0/path/win32.tsDownload https://deno.land/std@0.50.0/path/posix.tsDownload https://deno.land/std@0.50.0/path/common.tsDownload https://deno.land/std@0.50.0/path/separator.tsDownload https://deno.land/std@0.50.0/path/interface.tsDownload https://deno.land/std@0.50.0/path/glob.tsDownload https://deno.land/std@0.50.0/path/_constants.tsDownload https://deno.land/std@0.50.0/path/_util.tsDownload https://deno.land/std@0.50.0/fmt/colors.tsDownload https://deno.land/std@0.50.0/testing/diff.tsDownload https://deno.land/std@0.50.0/path/_globrex.tsDownload https://deno.land/std@0.50.0/async/deferred.tsDownload https://deno.land/std@0.50.0/async/delay.tsDownload https://deno.land/std@0.50.0/async/mux_async_iterator.tsDownload https://deno.land/std@0.50.0/textproto/mod.tsDownload https://deno.land/std@0.50.0/http/http_status.tsDownload https://deno.land/std@0.50.0/bytes/mod.tshttp://localhost:8000/


浏览器打开http://localhost:8000/,就可以看到输出的Hello World了。

从上面的例子可以看到,启动脚本时,deno会实时下载依赖到本地,下载完成后,再执行脚本逻辑。当我们control+C退出后,再次执行脚本:


> deno --allow-net server.tshttp://localhost:8000/


这一次不会再下载依赖了。


deno在第一次下载后,将依赖保存到了本地,并且这些依赖代码本身对用户是不可见的。这点和Node.js的node_modules完全不同。


如果我们想重新下载依赖,需要在执行脚本的时候加上--reload:deno --allow-net --reload server.ts


如果我们想查看脚本的依赖树,需要执行deno info server.ts :


> deno info server.ts local: /Users/pankeyu/Desktop/server.tstype: TypeScriptcompiled: /Users/pankeyu/Library/Caches/deno/gen/file/Users/pankeyu/Desktop/server.ts.jsmap: /Users/pankeyu/Library/Caches/deno/gen/file/Users/pankeyu/Desktop/server.ts.js.mapdeps:file:///Users/pankeyu/Desktop/server.ts  └─┬ https://deno.land/std@0.50.0/http/server.ts    ├── https://deno.land/std@0.50.0/encoding/utf8.ts    ├─┬ https://deno.land/std@0.50.0/io/bufio.ts    ...


上面的简单例子还体现出下面几点:

  1. deno原生支持了typescript。实际上,deno内置了ts引擎,会将ts代码解析为js代码后,交给v8运行。
  2. deno原生支持了top-level-await。
  3. 启动上面的示例脚本时,如果没有加上--allow-net这个flag,是会报错的。可以看出deno在安全方面的考量。

Deno的http server性能


Deno 是一个合适的异步服务器,每秒 25k 请求足以满足大多数目的,此外,由于普遍使用 Promise,Deno 需要有更好的尾部延迟。目前 Deno HTTP 服务器每秒处理约 25 000 个请求,最大延迟为 1.3 毫秒,与之相比,Node 程序每秒处理 34 000 个请求,最大延迟介于 2 到 300 毫秒之间。

这样看来,作者认为 Deno 的 HTTP 服务器还有更多的性能优势,并表示希望在将来的版本中实现这一目标。

deno的http server性能可以在这里查看:https://deno.land/benchmarks


Deno中的依赖与模块


在Node中,提供了许多的内置模块,如:


const fs = require('fs');const path = require('path');...


在deno中,也提供了不少的内置模块,但是并不支持Node一样的引入方式,而是挂在Deno这个全局变量上。看一个例子:


// denoFs.jsconst readFile = Deno.readFile;const serverBuffer = await readFile('./server.ts');console.log(serverBuffer);


执行脚本:


> deno run --allow-read  denoFs.jsUint8Array(213) [  105, 109, 112, 111, 114, 116,  32, 123,  32, 115, 101, 114, 118, 101,   32, 125,  32, 102, 114, 111, 109,  32,  34, 104, 116, 116, 112, 115,   58,  47,  47, 100, 101, 110, 111,  46, 108,  97, 110, 100,  47, 115,  116, 100,  64,  48,  46,  53,  48,  46,  48,  47, 104, 116, 116, 112,   47, 115, 101, 114, 118, 101, 114,  46, 116, 115,  34,  59,  10,  99,  111, 110, 115, 116,  32, 115,  32,  61,  32, 115, 101, 114, 118, 101,   40, 123,  32, 112, 111, 114, 116,  58,  32,  56,  48,  48,  48,  32,  125,  41,  ... 113 more items]


deno的模块化完全遵循了es module。从前面的例子可以看出,deno可以直接import线上的资源包。对于本地资源,使用本地路径引入即可,但是必须要带上资源后缀(.ts,.js)。import就是申明依赖。


// world.tsexport const world:string = 'world';
// hello.tsimport { world } from './world.ts';console.log(`Hello ${world}`);


执行脚本deno run hello.ts


> deno run hello.tsCompile file:///Users/pankeyu/Desktop/hello.tsHello world



Deno的内置工具


前面我们提到,deno原生支持打包,测试,格式化等。我们来试一试吧。


  • 打包

我们使用上面的denoFs.js作为例子。


> deno bundle denoFs.js denoFs.output.jsBundling file:///Users/pankeyu/Desktop/deno/denoFs.jsEmitting bundle to "denoFs.output.js"2482 bytes emmited.


最终输出了一个denoFs.output.js文件,大概长成下面的样子,这个js文件也是可以直接由deno运行的。


// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This is a specialised implementation of a System module loader.
// @ts-nocheck/* eslint-disable */let System, __instantiateAsync, __instantiate;
(() => {  const r = new Map();
  System = {    register(id, d, f) {      r.set(id, { d, f, exp: {} });    },  };
  async function dI(mid, src) {    ...  }
  function gC(id, main) {    ...  }
  function gE(exp) {    ...  }
  function rF(main) {    ...  }
  async function gExpA(id) {    ...  }
  function gExp(id) {    ...  }
  __instantiateAsync = async (m) => {    ...  };
  __instantiate = (m) => {    ...  };})();
"use strict";const readFile = Deno.readFile;const serverBuffer = await readFile("./server.ts");console.log(serverBuffer);
__instantiate("denoFs");

  • 测试

我们使用上面的world.ts作为例子。


// world.tsexport const world:string = 'world';


deno会从当前目录开始,逐级向上读取文件名为{*_,}test.{js,ts,jsx,tsx}文件作为测试文件。我们先写好测试用例:


// world.test.tsimport { world } from "./world.ts";Deno.test("env", () => {  if (world !== 'world') {    throw Error("wrong!");  }});


执行 deno test:


Compile file:///Users/pankeyu/Desktop/deno/.deno.test.tsrunning 1 teststest env ... ok (4ms)
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (4ms)

  • 格式化代码


假设我们待格式化的代码为:


// server.tsimport { serve } from "https://deno.land/std@0.50.0/http/server.ts";  const s = serve({ port: 8000 });console.log("http://localhost:8000/");for await (const  req of   s) {        req.respond({ body: "Hello World\n" })}


执行deno fmt server.ts后,代码格式化完成:


// server.tsimport { serve } from "https://deno.land/std@0.50.0/http/server.ts";const s = serve({ port: 8000 });console.log("http://localhost:8000/");for await (const req of s) {  req.respond({ body: "Hello World\n" });}


总结


通过上面的探索,结合之前Ryan Dahl提到的Nodejs的"设计错误",可以稍微总结一下deno了。


1、deno重新实现了模块化机制,采用去中心化的设计,支持直接import线上的资源,不再像Node一样依赖npm,摆脱了node_modules。同时,deno官方也提供了一个第三方库仓库:https://deno.land/std/

2、deno的内置模块是挂在全局变量上的。

3、deno内置了typescript解析引擎,原生支持typescript。并且,deno也在拥抱W3C的规范(deno支持fetch)。

4、deno默认是安全的。从上面的例子中就可以看出,想要访问网络,访问文件系统等,都需要加上特定的参数才可以。

5、deno原生支持打包,测试,代码格式化等操作,旨在提高项目的构建效率。


deno可以说是在重塑之前Nodejs的开发模式,其设计思想相比于Node.js,确实有进步的地方。对比作者之前提到的几条Node.js的"设计错误",deno一一解决了。

deno让人眼前一亮的去中心化模块依赖,或许可以让前端cdn、生产环境自动化部署等技术得到进一步发展。不过deno想要达到Node.js的稳定性以及繁荣的生态,还有很长的路要走。


写在后面


本文通过一个例子,不完整地对deno进行了介绍。Ryan Dahl大号练废了,又开了一个小号修炼。那么,这一次,你认为deno会火吗?

相关文章
|
1月前
|
Web App开发 JavaScript 前端开发
探索Deno:新一代JavaScript/TypeScript运行时环境
【10月更文挑战第25天】Deno 是一个新兴的 JavaScript/TypeScript 运行时环境,由 Node.js 创始人 Ryan Dahl 发起。本文介绍了 Deno 的核心特性,如安全性、现代化、性能和 TypeScript 支持,以及开发技巧和实用工具。Deno 通过解决 Node.js 的设计问题,提供了更好的开发体验,未来有望进一步集成 WebAssembly,拓展其生态系统。
|
1月前
|
JavaScript 安全 前端开发
探索Deno 1.x:安全JavaScript/TypeScript运行时的新篇章
【10月更文挑战第21天】Deno 1.x 是由Node.js创始人Ryan Dahl发起的项目,旨在解决Node.js的安全和模块化问题。Deno 1.x 版本带来了统一的运行时、默认安全、ES模块支持和内置TypeScript支持等新特性。其安全模型基于最小权限原则、沙箱环境和严格的远程代码执行控制,适用于Web服务器、命令行工具、桌面和移动应用及微服务开发。本文探讨了Deno 1.x的核心特性、安全模型及其在现代Web开发中的应用。
|
2月前
|
JavaScript 安全 前端开发
掌握Deno:新一代安全的JavaScript和TypeScript运行时
【10月更文挑战第15天】Deno是由Node.js创始人Ryan Dahl发起的新一代JavaScript和TypeScript运行时,旨在解决Node.js的设计问题,提供更安全、现代的开发体验。本文介绍Deno的核心特性、优势及使用方法,包括安全性、统一的运行时、现代Web标准和内置工具等,帮助开发者快速上手Deno,适用于Web开发、工具开发和教育等领域。
|
2月前
|
JavaScript 前端开发 安全
探索Deno:现代JavaScript/TypeScript运行时的崛起
【10月更文挑战第17天】Deno是由Node.js创始人Ryan Dahl发起的现代JavaScript/TypeScript运行时,强调安全性、TypeScript原生支持、统一的运行时环境和现代HTTP客户端。本文深入探讨了Deno的特性、优势及其在业界的应用,展示了它如何提升开发效率和代码安全性。
|
2月前
|
JavaScript 前端开发 安全
探索Deno 1.x:新一代JavaScript/TypeScript运行时
【10月更文挑战第16天】Deno 1.x是由Node.js创始人Ryan Dahl发起的新一代JavaScript/TypeScript运行时,自2018年首次亮相以来备受关注。本文介绍了Deno 1.x的新特性,如标准化模块、更严格的安全模型、改进的TypeScript支持和插件系统,探讨了其在现代Web开发中的潜在影响,并提供了如何开始使用Deno进行开发的指南。
|
2月前
|
JavaScript 前端开发 安全
探索Deno:新时代的JavaScript/TypeScript运行时
【10月更文挑战第1天】Deno是由Node.js创始人Ryan Dahl发起的JavaScript/TypeScript运行时,基于V8引擎,旨在提供安全、现代的开发环境。其核心优势包括默认安全性、内置TypeScript支持、统一的运行时及现代化API。Deno采用细粒度权限系统和ES模块系统,并提供内置测试与调试工具。尽管生态系统仍在发展中,学习曲线和兼容性问题存在,但Deno凭借其先进特性正逐渐成为开发领域的有力竞争者。
|
7月前
|
JavaScript 前端开发 测试技术
JS三大运行时全面对比:Node.js vs Bun vs Deno
JS三大运行时全面对比:Node.js vs Bun vs Deno
255 0
|
7月前
|
JSON Rust JavaScript
Deno 下一代JavaScript运行时
Deno 下一代JavaScript运行时
|
JSON Rust JavaScript
Deno 2021 回顾:优化 Deno 内核、兼容 Node.js、Deno 2 路线图将至
Deno 2021 回顾:优化 Deno 内核、兼容 Node.js、Deno 2 路线图将至
272 0
Deno 2021 回顾:优化 Deno 内核、兼容 Node.js、Deno 2 路线图将至
|
Rust JavaScript 前端开发
Deno 1.0 发布:为 JavaScript 和 TypeScript 提供安全运行时环境
经过了为期 2 年的开发,Deno 终于在 2020 年的 5 月份完成了 1.0 版本。其官方网站宣称,Deno 为 JavaScript 和 TypeScript 提供了一个安全的运行时环境。