前言

Ryan Dahl之父发布了新的项目Deno,很多IT媒体都使用了标题“下一代Nodejs”,首先我们看一下Deno的特性:

1.支持typescript (nodejs目前也支持)。

2.无package.json,无npm,不兼容nodejs。

3.通过URL的方式引入依赖而非引入本地模块,并在第一次运行的时候进行加载和缓存。

4.可以控制文本系统和网络访问权限以运行沙盒代码,默认访问只读文件系统可访问,无网络权限。

5.发生未捕捉错误时自动终止运行(这一点与nodejs一样)。

6.支持top-level的await。

7.最终创建单一可执行文件(go语言特性)。

8.可以作为库引入,用于建立自己的Javascript Runtime。

8项特性中,有好几个都是针对Node的痛点,包括无package.json,依赖包的引入,针对的就是被广泛吐槽的过大node_module。

附赠Deno Github地址:https://github.com/ry/deno

Deno详解

先上一张图来看一下javascript的发展简史。

目前Deno只是一个demo,我花了一段时间,读了一下deno的源码,整个源码并没有提到nodejs。

在 high-level 层面,Deno 提供了一个尽可能简单的 V8 到系统 API 的绑定。为什么使用 Golang 替代 C++ 呢,因为相比 Node 而言,Golang 让我们更加容易的添加新特性

我们再对比一下两者的启动性能。分别运行:

console.log('Hello world')

依然是相差悬殊,毕竟 deno 需要加载一个 TypeScript 编译器。毕竟是一个 demo 版本,希望以后用力优化。

对于性能提升还有一个思路就是,可以使用 LLVM 作为后端编译器把 TypeScript 代码编译为 WebAssembly 然后在 V8 里面运行,甚至可以直接把源码编译成二进制代码运行。Ryan Dahl 表示 deno 只需要一个编译器,那就是 TS。但是既然 deno 要兼容浏览器,那么 WebAssembly 应该也会被支持。

Deno 可以对 ts 的编译结果进行缓存(~/.deno/cache),所以目前关注的就是启动速度和初次编译速度。

要么就是在发布前先行编译,如此一来 deno 就脱离了开发的初衷了。deno 是一个 ts 的运行时,那么就应该可以直接运行 ts 代码,如果提前把 ts 编译成 js,那么 deno 就回退到 js 运行时了。

初学者应该学习Node还是Deno

对于这个问题,Ryan Dahl 的回答干净利落:

Use Node. Deno is a prototype / experiment.

使用 Node。Deno 只是一个原型或实验性产品。

从介绍可以看到,Deno 的目标是不兼容 Node,而是兼容浏览器。

所以,Deno 不是要取代 Node.js,也不是下一代 Node.js,也不是要放弃 npm 重建 Node 生态。deno 的目前是要拥抱浏览器生态。

不得不说这个目标真伟大。Ryan Dahl 开发了 Node.js,社区构建出了整个 npm 生态。并且“Node.js 是前端工程化的重要支柱之一”。

虽然后来 Ryan Dahl 离开 Node.js 去了 Golang 社区,但是现在 Ryan Dahl 又回来了,为 JavaScript 社区带来了 Golang,开发出了 Deno,然后拥抱浏览器生态。

我们看看 deno 的关于 Web API 的目标:

  • High level

    • Console √
    • File/FileList/FileReader/Blob
    • XMLHttpRequest
    • WebSocket
  • Middle level

    • AudioContext/AudioBuffer
    • Canvas

甚至还会包括 webGL 和 GPU 等的支持。

Deno的架构

Parsa Ghadimi 绘制了一张关于 Deno 的架构图

底层使用了作者开发的 v8worker2,而 event-loop 则基于 pub/sub 模型。

我比较好奇的是 deno 使用了 protobuf,而没有使用 Mojo。既然目标是要兼容浏览器,却不使用 Mojo,而是要在 protobuf 上重新造轮子,可见 Ryan Dahl 是真正的“轮子哥”啊。但是从 issue 中可以看出,Ryan Dahl 之前是没有听说过 Mojo 的,但是他看完 mojo 之后,依然觉得 protobuf 的选择是正确的。

Mojo 是 Google 开发的新一代 IPC 机制,用以替换旧的 Chrome IPC。目前 Chrome 的最新版本是 67,而 Google 的计划是在 2019 年的 75 版本用 mojo 替换掉所有的旧的 IPC。

Mojo 的思路确实和 protobuf 毕竟像,毕竟都是 Google 家的。旧的 IPC 系统是基于在 2 个进程(线程)之间的命名管道(IPC::Channel)实现的。这个管道是一个队列,进程间的 IPC 消息按照先进先出的顺序依次传递,所以不同的 IPC 消息之间有先后次序的依赖。相比之下,Mojo 则为每一个接口创建了一个独立的消息管道,确保不同接口的 IPC 是独立的。而且为接口的创建独立的消息管道的代价也并不昂贵,只需分配少量的堆内存。

Mojo 的架构设计:

我们可以看一下 Chrome 引入 Mojo 之后的架构变化。

之前:

之后:

是不是有点微服务的感觉。

熟悉 Java 的 Spring 的可以明显看出这个依赖倒置。Blink 本来是浏览器最底层的排版引擎,通过 Mojo,Blink 变成了要给中间模块。最近大热的 Flutter 也是基于 Mojo 架构的。

TypeScript & Javascript

deno 的介绍是一个安全的 TypeScript 运行环境。但是我们看源码就会发现,deno 集成进了一个 TypeScript 编译器,而入口文件中 ry/deno:main.go

// It's up to library users to call
// deno.Eval("deno_main.js", "denoMain()")
func Eval(filename string, code string) {
err := worker.Load(filename, code)
exitOnError(err)
} // It's up to library users to call
// deno.Eval("deno_main.js", "denoMain()")
func Eval(filename string, code string) {
err := worker.Load(filename, code)
exitOnError(err)
}

使用 V8 运行的 deno_main.js 文件。是 JavaScript 而不是 TypeScript 。

在前面的分析中我们知道这会影响 deno 的初次启动速度。那么对于执行速度呢?从理论上,TypeScript 作为一种静态类型语言,编译完成的 JavaScript 代码会有更快的执行速度。我之前在《前端程序员应该懂点V8 知识》曾经提到过 V8 对于 JavaScript 性能提升有一项是 Type feedback

当 V8 执行一个函数时,会基于函数传入的实参(注意是实参,而不是形参,因为 JavaScript 的形参是没有类型的)进行即时编译(JIT):

但是当后面再次以不同的类型调用函数时,V8 会进行去优化(Deopt)操作。

(将之前优化完的结果去掉,称为“去优化”)

但是如果我们使用 TypeScript ,所有的参数都是由类型标注的,因此可以防止 V8 引擎内部执行去优化操作。

对deno性能的展望

虽然 TypeScript 可以避免 V8 引擎的去优化操作,但是 V8 执行的是 ts 编译后的结果,我们通过字节码或者机器码可以看到,V8 依然生成了 Type Check 的代码,每次调用函数之前,V8 都会对实参的类型进行检查。也就是说,虽然 TypeScript 保证了函数的参数类型,但是编译成 JavaScript 之后,V8 并不能确定函数的参数类型,只能通过每次调用前的检查来保证参数的类型。

其次,当 V8 遇到函数定义时,并不知道参数的类型,而只有函数被调用后,V8 才能判断函数的类型,才对函数进行 Typed 即时编译。这里又有一个矛盾了,typescript 在函数定义时就已经知道了形参的类型,而 V8 只有在函数调用时才根据实参的类型进行优化。

所以,目前 deno 的架构还存在很多问题,毕竟只是一个 demo。未来还有很多方向可以优化。

V8 是一个 JavaScript 运行时,而 deno 如果定义为“安全的 TypeScript 运行时”,至少在目前的架构上,性能是有很大损失的。但是目前还不存在一个 TypeScript 运行时,退而求其次只能在 V8 前面放一个 TypeScript 编译器了。

执行流程是这样的:

虽然我在项目中没有使用过 TypeScript ,但是基本上我在项目里面写的第三方库都会提供一d.ts 文件。目前 TypeScript 最大的用途还是体现在开发和维护过程中。

我们想到的一个方式就是 fork 一份 V8 的源码,然后把编译流程整合进去。TypeScript 在编译为 JavaScript 的过程中也需要一份 AST,然后生成 js 代码。V8 执行 js 代码是再 parse 一份 AST,基于 AST 生成中间代码(ByteCode)。如果 TypeScript 可以直接生成对用的字节码则会提升运行时的性能。

不过 Ryan Dahl 大概不会这么干。但是也未必,毕竟社区已经把 TypeScript 的一个子集编译为 WebAssembly 了。

之前微软的 JScript 和 VBScript 在和 JavaScript 的竞争中败下阵来,而现在 TypeScript 势头正猛。虽然对 ES 规范的兼容束缚了 TypeScript 的发展,但很期待微软可以提供一个 TS 运行时,或者在 Chakra 引擎增加对 TS 运行时的支持。

Deno下一代Nodejs?Deno初体验的更多相关文章

  1. Mac下nodeJS初体验

    Mac下nodeJS初体验 这两天博主出门在外,抽空体验一下大名鼎鼎的node 安装 brew install node 安装测试 $ node -v v8.4.0 运行本地脚本 用文本编辑器编辑一段 ...

  2. node.js 初体验

    node.js 初体验 2011-10-31 22:56 by 聂微东, 174545 阅读, 118 评论, 收藏, 编辑 PS: ~ 此篇文章的进阶内容在为<Nodejs初阶之express ...

  3. grunt 构建工具(build tool)初体验

    操作环境:win8 系统,建议使用 git bash (window下的命令行工具) 1,安装node.js 官网下载:https://nodejs.org/  直接点击install ,会根据你的操 ...

  4. gulp快速入门&初体验

    前言 一句话先 gulp 是一个可以简单和自动化"管理"前端文件的构建工具 先说我以前的主要工作,我主要是做游戏服务端的,用c++/python,所以我对东西的概念理解难免要套到自 ...

  5. node.js + express 初体验【hello world】

    [node.js]  一个神奇的XX 呵呵 :) 不知道怎么形容他才好! [express] 是node.js 开发web应用程序的框架 开发环境:XP 大家共同进步吧 :) 一:前期准备: 1:下载 ...

  6. ionicframework I ------------- 初体验

    ionicframework I -------------  初体验 Create hybrid mobile apps with the web technologies you love. Fr ...

  7. Node.js 网页瘸腿爬虫初体验

    延续上一篇,想把自己博客的文档标题利用Node.js的request全提取出来,于是有了下面的初哥爬虫,水平有限,这只爬虫目前还有点瘸腿,请看官你指正了. // 内置http模块,提供了http服务器 ...

  8. AntDesign初体验

    AntDesign初体验 作为一个java开发也需要掌握一定的前端开发技能,毕竟靠人不如靠自己.再者,有时候一些小的改动自己就可以搞定了,就不用低三下四去求别人了: 安装Nodejs $ npm in ...

  9. Dapr初体验之服务调用

    初次理解服务调用 在微服务中,有一个难点就是:如果你想使用各个服务组件,你就得知道不同服务的地址和端口,也就是服务发现. 在传统应用我们是怎么做的?就是在web项目里配置上api地址,如下: 在一个w ...

随机推荐

  1. wap2app(七)-- 长按保存图片

    用Hbuilder打包网站,在打包好的app中是无法像网站那样直接使用长按图片保存的功能的,需要在网站里对来自wap2app进行单独处理,接下来介绍一下如何在Hbuilder打包后的app里实现长按图 ...

  2. java后台打开浏览器代码

    import java.awt.Desktop; import java.io.IOException; import java.net.URI; import java.net.URISyntaxE ...

  3. exports与module.exports的区别,export与export.defult区别

    在JS模块化编程中,之前使用的是require.js或者sea.js.随着前端工程化工具webpack的推出,使得前端js可以使用CommonJS模块标准或者使用ES6 moduel特性. 在Comm ...

  4. katalon之web文件上传

    参考:https://docs.katalon.com/katalon-studio/docs/webui-upload-file.html#example- 适用范围:tag=input, type ...

  5. html留言功能

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  6. SQL SERVER 查询表的行数

    SELECT OBJECT_NAME(ii.id) TableName ,rows FROM sysindexes ii INNER JOIN sysobjects oo ON ( oo.id = i ...

  7. Linux环境下执行java -jar xxx.jar命令如何让springboot项目在后台运行

    段落引用> 由于springboot内置了tomcat容器,我们通常会把项目打成jar或者war后直接使用java -jar xxx.jar命令去运行程序,但是当前ssh窗口被锁定或者按下ctr ...

  8. ELK环境配置+log4j日志记录

    ELK环境配置+log4j日志记录 1. 背景介绍 在大数据时代,日志记录和管理变得尤为重要. 以往的文件记录日志的形式,既查询起来又不方便,又造成日志在服务器上分散存储,管理起来相当麻烦, 想根据一 ...

  9. Postgresql的隐藏系统列

    转自 https://www.2cto.com/database/201206/137301.html   Postgresql的隐藏系统列   和oracle数据库一样,postgresql也有自身 ...

  10. Tomcat配置自定义JAVA环境

    Tomcat的bin目录下 在setclasspath.sh(Linux系统,Windows系统为setclasspath.bat)文件的开头添加: export JAVA_HOME=/usr/lib ...