客觀對比Node 與 Golang

Go僅用標準庫就能寫大多數的軟件。用Node.js時,咱們幾乎都是不得不引入一個外部的庫, 這樣作既增長了部署的時間,也增長了來自第三方軟件的潛在隱患。只用標準庫能讓咱們寫的代碼更快更安全。javascript

另外值得一提的是,node的代碼在跨平臺運行時,有時會碰到各類意想不到的問題,而go語言的代碼實現跨平臺運行時僅僅配置一下gopath便可完美兼容。php

d

包管理

Go對包管理必定有本身的理解。對於包的獲取,就是用go get命令從遠程代碼庫(GitHub, Bitbucket, Google Code, Launchpad)拉取。而且它支持根據import package分析來遞歸拉取。這樣作的好處是,直接跳過了包管理中央庫的的約束,讓代碼的拉取直接基於版本控制庫,你們的協做管理都是基於這個版本依賴庫來互動。細體會下,發現這種設計的好處是去掉冗餘,直接複用最基本的代碼基礎設施。Go這麼幹很大程度上減輕了開發者對包管理的複雜概念的理解負擔,設計的很巧妙。java

可是這樣也會產生一系列的問題:node

  • 缺少明確顯示的版本。團隊開發不一樣的項目容易導入不同的版本,每次都是get最新的代碼。尤爲像我司對開源軟件管理很是嚴格,開源申請幾乎是沒法實施。linux

  • 第三方包沒有內容安全審計,獲取最新的代碼很容易引入代碼新的Bug,後續運行時出了Bug須要解決,也沒法版本跟蹤管理。git

  • 依賴的完整性沒法校驗,基於域名的package名稱,域名變化或子路徑變化,都會致使沒法正常下載依賴。咱們在使用過程,發現仍是有很多間接依賴包的名稱已失效了(不存在,或又fork成新的項目,舊的已不存維護更新)。github

而Go官方對於此類問題的建議是把外部依賴的代碼複製到你的源碼庫中管理。把第三方代碼引入本身的代碼庫仍然是一種折中的辦法。golang

因而市面上就誕生了各類Go包管理工具,如glide,dev等。使用第三方包管理最大的好處是,每一個項目都採用各自獨立的包,並且能夠很好的控制包的版本,這在團隊開發中尤爲重要。數據庫

而node的包管理我認爲就相對好一些了,不論是npm仍是yarn的包版本控制,都是棒棒噠。npm

其中還有一點須要注意的地方,就是glide的依賴是扁平化的,Glide 獲取的全部依賴都放置在項目頂級目錄下的vendor/中,而node中的依賴是集中存放在node_modules目錄下,鏈式依賴過多,而且是遞歸查找。

類型系統

node是使用JavaScript這門動態語言、弱類型語言,好處天然不言而喻,比較靈活,忽略驗證數據的類型和真值判斷陷阱所帶來的額外負擔。可是JavaScript是在運行時進行解釋的,這可能會致使錯誤處理和調試的問題。

go屬於靜態語言,也是強類型語言,雖然沒有動態語言靈活,但有助於數據完整,並能夠在編譯時查找類型錯誤。Go 被直接編譯成機器碼,這就是它速度的來源。使用編譯語言調試是至關容易的,由於你能夠在早期捕獲大量錯誤。

併發處理

node

node只適合IO密集型,它沒有提供太多的併發基元。惟一能同時運行的是I/O程序和定時器等,並不適合CPU密集型。

node運行機制:node運行機制是事件循環機制,每次從事件隊列中取出一個函數之類的,而後去運行它,若是過程當中發生IO事件,好比利用fs模塊寫一個文件,或者去數據庫查詢信息等,node就會將這個IO操做加入到一個線程池中去執行,事件循環在主線程繼續執行,當線程池中的事件執行完畢,就會將這個結果放入到主線程中。可是若是遇到計算密集型的任務,由於node是單線程,就會阻塞主線程直到該任務執行完畢纔會往下執行,因此node不適合作CPU密集型。

d

go

go適合IO密集型一樣也適合CPU密集型,你能夠在程序運行的任何階段,建立goruntine去實現併發,而且go提供了channel來實現協程間通訊,很贊有木有。

在操做系統提供的內核線程之上,Go搭建了一個特有的兩級線程模型。goroutine是實際併發執行的實體,每一個實體之間是經過channel通信來實現數據共享。關於go的併發及調度原理,戳這裏goroutine 調度原理

d

錯誤處理

Go 推薦在錯誤出現的地方捕獲它們,而不是像 Node 同樣在回調中讓錯誤冒泡。

node的錯誤處理是錯誤前置,golang的錯誤處理是錯誤後置。

// Node 的錯誤處理
foo('bar', function(err, data) {
// 處理錯誤
}
複製代碼
//Go 的錯誤處理
foo, err := bar()
if err != nil {
// 用 defer、 panic、 recover 或 log.fatal 等等處理錯誤.
}
複製代碼

Go 中的錯誤處理分爲錯誤和異常兩種,那麼錯誤和異常的區別是什麼呢?

錯誤和異常從語言機制上面講,就是error和panic的區別

  • 錯誤是指可能出現的地方出了問題,好比打開一個文件失敗,這種是在人們的意料之中;

  • 而異常指的是不該該出現問題的地方出現了問題,好比引用了空指針、下標越界、除數爲0等,這種狀況在人們的意料以外。

Golang中引入兩個內置函數panic和recover來觸發和終止異常處理流程,同時引入關鍵字defer來延遲執行defer後面的函數。

使用 Go 的錯誤處理時,應注意如下幾點

  • 失敗的緣由只有一個時,不使用error

  • 沒有失敗時,不返回error

  • error應放在返回值類型列表的最後

  • 錯誤值統必定義,而不是跟着感受走

  • 錯誤逐層往上拋時,層層都加日誌,便於定位錯誤

  • 當嘗試幾回能夠避免失敗時,不要當即返回錯誤

  • 當上層函數不關心錯誤時,建議不返回error

Node中的錯誤處理主要分爲如下三種狀況

  • 異步的函數裏,使用throw。使用者使用try...catch便可捕獲錯誤。

  • 異步函數裏,更經常使用的方式是使用callback(err, result)的方式。

  • 在更復雜的場景裏,能夠返回一個EventEmitter對象,代替使用callback。使用者能夠監聽emitter對象的 error事件。 例如讀取一個數據流,咱們可能會同時使用 req.on('data')、req.on('error')、req.on('timeout') 。

因此,使用throw仍是callbacks、EventEmitter,取決於:

  • 該錯誤是操做錯誤仍是編碼錯誤?

  • 該函數是同步仍是異步?

測試

在node中進行單元測試須要藉助第三方測試框架入mocha以及第三方斷言庫入should.js,相關文章 Node.js 單元測試:我要寫測試

使用Go的時候,咱們喜歡測試框架的規範化。在Go裏,全部的測試包都是內置的。若是你須要寫一個新的測試套件,你必須作就是把(文件名)_test.go文件加到你要測試的軟件的同一個包裏,它將會在你每次執行go test的時候運行。

提到單元測試,就不得不提的是測試的覆蓋率問題,在go中的測試覆蓋率有一點須要注意的地方,在go中計算單元測試覆蓋率是不包括沒有定義_test.go的模塊的,只會統計已經定義了_test.go模塊的單元測試覆蓋率。

部署

go的部署真的是很是簡單,將go build後生成的二進制文件直接丟到服務器上去,而後運行這個程序,不須要任何語言環境,像java程序須要在服務器安裝java,php須要安裝Apache,PHP等運行環境,go通通不須要,只須要一個linux系統就好,扔上去就能夠了。

而node的部署的部署則須要在服務器上安裝npm,或者藉助pm2,將項目代碼拉倒服務器,並跑起來。

社區

Node 和 Go 歲數相仿,社區也相對都比較完整了

做者的 Golang 系列博文:

剖析 golang 的25個關鍵字

Array、Slice、Map原理淺析

Go 與 Node 內存分配與垃圾回收

goroutine 調度原理

相關文章
相關標籤/搜索