🕵️♂️一塊兒認識Deno

動態語言都是很是實用的工具,用戶能夠經過腳本把很是複雜的系統給連接到一塊兒,而且不用花費心思去考慮內存管理等問題。html

JavaScript 是應用最普遍的動態語言,只需一個 Web 瀏覽器就能在全部設備上運行。而Node.js是一個基於Chrome V8引擎的JavaScript運行時(能夠理解爲一個容器,提供JavaScript解析+各類能力)。前端

🤔️Node.js怎麼了?

image.png

Node.js誕生2009年,它的到來對前端領域產生了很是重大的影響,它也使得先後端使用同一種語言,統一模型的夢想得以實現。可是在這十多年間,強大的Node.js也慢慢地暴露出了它的缺點。在2018年,Node.js之父Ryan Dahl發表了一篇演講,在此次演講中他提到了「Node.js令我感到遺憾的10件事」。node

1. 沒有堅持使用Promise

在Node.js中,對於異步處理同時存在兩種方式:callback寫法與Promise寫法。在8.0版本之前,Node.js的異步API基本上都是用callback的方式來寫的:webpack

fs.readFile('文件.txt', data, (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});
複製代碼

爲了靠近Promise,一方面Node.js慢慢增長了一部分Promise寫法的API,另外一方面在util包中增長了一個promisify接口用於把回調方式的API轉換爲Promise方式:git

const {promisify} = require('util')
const readFile = promisify(fs.readFile)
readFile('./conf.js').then(data=>console.log(data))
複製代碼

2. 沒有足夠的安全性

在Node.js中,任何人編寫的程序均可以隨意地訪問系統和網絡,這將會很容易致使安全問題。例如:假如咱們經過npm安裝了一個依賴a-mod,但不少狀況下咱們並不知道這個包內部的代碼邏輯是怎麼樣的,它有可能會在提供服務的同時,在咱們絕不知情的狀況下偷偷地刪除咱們本地的文檔(只是惡趣味),甚至更危險的事情。github

3. node_modules

隨着Node.js的發展,node_modules很容易變得愈來愈大愈來愈沉重,而且模塊的解析複雜度也在隨着它增大而增大。web

image.png

......

🤯Deno又是啥?

2020年5月13日,Deno 1.0正式發佈,它正是出於咱們上文中提到的Node.js的做者Ryan Dahl之手。而Deno與Node.js同樣,都是一個基於Chrome V8引擎的JavaScript運行時。經過它的名字(no與de的拼接),結合做者在18年時對Node.js的吐槽,雖然咱們不能認定Deno會是Node.js的替代品,可是它確定是一個避免了Node.js某些設計缺陷的新嘗試。npm

1. 統一使用Promise接口

與Node.js不一樣,Deno統一使用Promise接口,配合async寫法使得整個系統變得流暢和統一了。編程

// Deno.create方法能夠建立或讀取一個文件
const file = await Deno.create("./foo.txt");
console.log(file);
複製代碼

值得一提的是,Deno支持 top-level-await,即咱們能夠直接在最外層代碼中使用await關於top-level-await的更多信息能夠參考如下文章:Top-level awaitjson

2.內置Typescript

若是咱們要在 Deno 中使用TypeScript的話,無需執行任何操做。沒有Deno時,咱們必需要將咱們編寫的TypeScript代碼編譯爲JavaScript纔可以運行。Deno將會直接在它內部進行這個編譯的過程,下降了上手的成本。

3. 兼容ES6模塊語法

Node.js模塊遵循的是CommonJS規範,這就致使了它沒法完美兼容ES6的module語法。而Deno使用了TypeScript語言,這將徹底兼容ES模塊(TypeScript也有一套它本身的模塊管理規範,但同時兼容ES6 module語法)。若是想要再瞭解一下這些模塊管理規範的區別的話,能夠參考如下文章:exports、module.exports 和 export、export default 究竟是咋回事

4.再也沒有node_modules

咱們在使用Node.js時,一般每一個工程都須要經過npm i來安裝所需依賴。npm的存在的優勢是集思廣益,極大地豐富了Node.js生態,爲使用者提供了又大又全的功能。可是它也有一些缺點,例如它致使全世界都被node_modules佔領了:一個發佈到npm上的包在全世界無數臺電腦上都有它各類版本的副本,這正是中心化的模塊存儲方式形成的。

Deno採用不強制中心化存儲方式,換句話說你能夠加載任何地方的模塊。

// 能夠直接經過url引入
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
複製代碼

它具備如下特色:

  • 再也不有中心化的包管理器了。你能夠直接經過url導入ECMAScript模塊;

  • 再也不有「神奇的」Node.js 模塊解析。如今語法是明確的,這讓各類事情更容易推理;

  • 再也不有node_modules目錄;

上述第一點提到的去中心化能夠說是Deno做出的一次勇敢的嘗試,可是它其實也有一些問題:

  • 實際上還存在一個node_modules(下文會提到)只是不會被用戶輕易看到;
  • 正常來講依賴的下載會放在第一次加載的時候(也能夠經過deno cache命令在不執行代碼的狀況下緩存依賴),因此總體看來第一次啓動仍是很慢的;
  • 很難控制版本,須要配合 deps.ts 使用(下文會提到);

既然Deno並無node_modules,那麼總得有一個地方存放依賴吧?

其實存放依賴的目錄是經過DENO_DIR這個環境變量來控制的(其實也是node_modules),它的初始值爲 $HOME/.deno

咱們能夠經過如下命令,查看當前電腦已經緩存的依賴:

tree $HOME/Library/Caches/deno
複製代碼

image.png

5. 使用dep.ts和url進行版本控制

基本上咱們每一個工程都是圍繞package.json創建的。它已經膨脹得很大了,其中包含許多職責,諸如:

  • 保留項目的元數據;

  • 列出項目依賴項和版本控制;

  • 將依賴項分類爲dpendenciesdevDependencies

  • 定義程序的入口點;

  • 存儲與項目相關的 Shell 腳本;

  • ......

相比於package.json最先的用意(可能只是描述一個包信息而已),它變得過於複雜。Deno選擇將它拋棄,利用deps.ts取而代之,進行版本控制(和咱們工程中Constant.js差很少)。

在內部,依賴項被從新導出。這就能讓應用程序中的不一樣模塊都引用相同的源。

export { assert } from "https://deno.land/std@v0.39.0/testing/asserts.ts";
export { green, bold } from "https://deno.land/std@v0.39.0/fmt/colors.ts";
複製代碼

若是要更新任何模塊,咱們只須要在deps.ts中更改url。

6. 具備安全機制

默認狀況下 Deno 中的代碼會在安全的沙箱中執行。未經容許,腳本沒法訪問硬盤驅動器、打開網絡鏈接或進行其餘任何可能引入惡意行爲的操做。瀏覽器提供了用於訪問相機和麥克風的 API,但用戶必須首先授予權限才能啓用它們。Deno在終端中提供了模擬行爲。

要查看權限示例的完整列表,請輸入如下命令:

deno run -h
複製代碼

image.png

7. 提供一套內置工具

在咱們開發的過程當中,不少時候須要使用一些實用工具(例如:webpack,babel,eslint,prettier......),Deno 內置了開發者須要的各類功能包括打包、格式美化、測試、安裝、文檔生成等軟件生命週期的各類功能。

deno bundle:將腳本和依賴打包
deno eval:執行代碼
deno fetch:將依賴抓取到本地
deno fmt:代碼的格式美化
deno help:等同於-h參數
deno info:顯示本地的依賴緩存
deno install:將腳本安裝爲可執行文件
deno repl:進入 REPL 環境
deno run:運行腳本
deno test:運行測試
複製代碼

Deno 自己就是一個完整的生態系統,具備運行時和本身的模塊/包管理系統。這纔有了更大的空間來內置全部工具。

雖然目前尚未辦法在Deno中替換整個前端構建管道,可是隨着Deno生態的發展,相信這一天已經不會太遠了。

8. 更靠近JavaScript API

Deno是精心設計的,避免偏離標準化的瀏覽器JavaScript API。Deno 1.0 提供如下與 Web 兼容的 API:

  • addEventListener
  • atob
  • btoa
  • clearInterval
  • clearTimeout
  • dispatchEvent
  • fetch
  • queueMicrotask
  • removeEventListener
  • setInterval
  • setTimeout
  • AbortSignal
  • Blob
  • File
  • FormData
  • Headers
  • ReadableStream
  • Request
  • Response
  • URL
  • URLSearchParams
  • console
  • isConsoleInstance
  • location
  • onload
  • onunload
  • self
  • window
  • AbortController
  • CustomEvent
  • DOMException
  • ErrorEvent
  • Event
  • EventTarget
  • MessageEvent
  • TextDecoder
  • TextEncoder
  • Worker
  • ImportMeta
  • Location

這些均可以在程序的頂級範圍內使用。這意味着若是你不去用Deno()命名空間上的任何方法,那麼你的代碼應該能同時與Deno和瀏覽器兼容。儘管這些Deno API並非都 100%符合其等效的Web規範,但這對前端開發人員而言仍然是一個很大的好處。

整體而言,若是服務端和瀏覽器端存在相同概念,Deno就不會創造新的概念。這一點其實Node.js也在作,旨在實現 Universal JavaScriptSpec compliance and Web Compatibility的思想,這是一個大趨勢。

9.標準庫

Deno團隊爲開發者提供了一個沒有外部依賴的、實用的、高頻的開發庫,減輕咱們開發的負擔:

  • node:node API 兼容模塊;
  • io:二進制讀寫操做;
  • http:網絡和 web 服務相關;
  • path:文件路徑相關;
  • colors:輸出有顏色的文字,相似 chalk 庫;
  • printf:格式化輸出,相似 C 語言的 printf;
  • tar:解壓與壓縮;
  • async:生成異步函數的;
  • bytes:二進制比較和查找等;
  • datetime:日期相關;
  • encoding:文本的與二進制的轉化、CSV和對象轉化、yarml 和對象轉化等;
  • flags:命令行參數解析;
  • hash:字符轉 sha1 和 sha256;
  • fs:文件系統模塊,相似 node 的 fs 模塊;
  • log:日誌管理;
  • permissions:權限相關;
  • testing:測試和斷言相關;
  • uuid:用於生成 UUID;
  • ws:WebSocket 相關;

從這個點上來看,Deno 既作運行環境又作基礎生態,有效緩解了npm生態下選擇困難症。集成了官方包對功能肯定的模塊來講是頗有必要的,並且提升了底層庫的穩定性,除此以外Deno生態也有三方庫,並且本質上三方庫和官方庫在功能上沒有任何壁壘,由於實現代碼都是相似的。

......

🤩總結

如下圖片歸納了Node與Deno之間的差別:

image.png

Deno的出現使人振奮,可是它仍不能徹底替代 Nodejs,這背後的緣由主要是歷史兼容成本,也就是完整支持整個Node生態不僅是設計的問題,更是一個體力活,須要一個個高地去攻克。

一樣的,Deno對Web的支持也讓人耳目一新,可是目前階段應該仍不能放到生產環境使用,除了官方和三方生態還在逐漸完善外,deno bundleTree Shaking能力的缺失以及構建產物沒法保證與如今的webpack徹底相同,這樣會致使對穩定性要求極高的大型應用遷移成本很是高。

最亮眼的改動是模塊化部分,依賴徹底去中心化從長遠來看是一個很是好的設計,只是基礎設施和生態要達到一個較爲理想的水平。

儘管Deno可能還沒法徹底替代Node.js,但它已經成爲了能夠平常使用的絕佳編程環境。

😘參考文檔

相關文章
相關標籤/搜索