Node.js真的無(wú)所不能?那些不適用的應(yīng)用領(lǐng)域分析
原創(chuàng)Node.js是一個(gè)服務(wù)器端JavaScript解釋器,底層采用的還是libevent;它的目標(biāo)是幫助程序員構(gòu)建高度可伸縮的應(yīng)用程序,目前對(duì)Node.js 的采用狀況,Node.js 官方站點(diǎn)有一些羅列,但是相當(dāng)不完整。如果你自己公司用到,也可以在 github 上提交自己的 pull-request 來(lái)更新這個(gè)文檔。
https://github.com/joyent/node/wiki/Projects,-Applications,-and-Companies-Using-Node
其實(shí)到今天為止,很少有哪些大的互聯(lián)網(wǎng)公司是和 Node.js 無(wú)關(guān)的。LinkedIn,Yahho,Paypal, eBay, Walmart 都在將既有的系統(tǒng)向 Node.js 遷移(https://www.quora.com/Node-js/What-companies-are-using-Node-js-in-production 翻墻看)。國(guó)內(nèi)的淘寶、網(wǎng)易、百度等也都有很多項(xiàng)目運(yùn)行在 Node.js 之上。
2011 年我開(kāi)始接觸 Node.js 的時(shí)候,npmjs.org 上只有不到 3,000 個(gè) Node.js 的 packages,今天(2014-3-2)則有 61,897 個(gè),這個(gè)數(shù)字還在快速增長(zhǎng)中。
下面有兩個(gè)鏈接,第一個(gè)是在講 Walmart 這幾年為什么以及如何遷移到 Node.js 上;第二個(gè)則為 eBay 是如何從 Node.js 的懷疑者轉(zhuǎn)變?yōu)椴捎谜摺?/p>
《Announcing ql.io》 這篇文章的最后一段,列出了 eBay 為什么選擇 Node.js。
每天都有幾百個(gè)新的 packages 被發(fā)布到 npm 上,小到幾行代碼,大到萬(wàn)行代碼的 Framework。一天有7百萬(wàn)次的包下載(安裝到某臺(tái)電腦上),對(duì)于單一開(kāi)發(fā)框架的社區(qū)來(lái)說(shuō),用沸騰的海洋來(lái)形容并不過(guò)分。
以下應(yīng)用領(lǐng)域和程序員不適合選擇Node.js:
- 計(jì)算密集型應(yīng)用。Javascript 的計(jì)算性能是很難和 C 語(yǔ)言代碼相比的。當(dāng)然,也有反例:http://onlinevillage.blogspot.jp/2011/03/is-javascript-is-faster-than-c.html,只不過(guò)不具有典型性。
- 需要精密控制內(nèi)存的分配和釋放的場(chǎng)景,如果用 Node.js 實(shí)現(xiàn) Redis 數(shù)據(jù)庫(kù),雖然程序會(huì)簡(jiǎn)單不少,但是 JVM 對(duì)內(nèi)存數(shù)據(jù)結(jié)構(gòu)的精密控制能力是比不了用 C 語(yǔ)言純手工打造的。
- 大量且需要頻繁通過(guò) C Binding 調(diào)用 C library 的情況。這種場(chǎng)景下,往返參數(shù)的 Marshal/Unmarshal 的成本可能會(huì)大于 C Library 帶來(lái)的性能提升。
- 實(shí)時(shí)性要求很高的場(chǎng)景,例如:交換機(jī)或者工控機(jī)器人。這是因?yàn)樗型ㄟ^(guò)垃圾回收機(jī)制來(lái)管理內(nèi)存的系統(tǒng)都有可能在 GC 過(guò)程中產(chǎn)生停頓,從而影響響應(yīng)速度,而且很難優(yōu)化。
- 需要單一進(jìn)程控制大內(nèi)存的場(chǎng)景:v8 引擎的設(shè)計(jì)限制,在 32-bit下有 1GB 最大堆尺寸的限制,在 64-bit下是1.7GB。當(dāng)然,由于 node.js buffer 的分配不是在 v8 的堆上,因此可以超過(guò)此限制。這個(gè)限制可以通過(guò)向 v8 引擎?zhèn)鬟fmax_old_space_size 參數(shù)來(lái)超越,但是也會(huì)帶來(lái) GC 的性能退化。這一問(wèn)題在幾乎所有 GC Based 的系統(tǒng)下都存在。
- 不關(guān)心系統(tǒng)吞吐率或者不需要異步調(diào)用的場(chǎng)景:例如,自動(dòng)化腳本,這些腳本不需要關(guān)心多用戶并發(fā)訪問(wèn)的性能消耗。用 Python 這樣的“膠水”語(yǔ)言寫(xiě)起來(lái)會(huì)更簡(jiǎn)單。
- 某些非通用場(chǎng)景:例如 nginx 對(duì)于靜態(tài) web server 或者 反向代理的場(chǎng)景是特別設(shè)計(jì)的,這些場(chǎng)景中 nginx 的性能比 Node.js 要好。
- 強(qiáng)類(lèi)型強(qiáng)迫癥:有些 Java 或者 .NET 過(guò)來(lái)的程序員會(huì)認(rèn)為只有強(qiáng)類(lèi)型語(yǔ)言和嚴(yán)格定義的類(lèi)型系統(tǒng)是專(zhuān)業(yè)化的象征,構(gòu)造這樣的系統(tǒng)是架構(gòu)師的使命,而動(dòng)態(tài)語(yǔ)言只是玩具,只能用來(lái)做 Demo 或者前端開(kāi)發(fā)。
- 團(tuán)隊(duì)成員難以理解或者接受函數(shù)式編程:Javascript 本質(zhì)上更像函數(shù)式語(yǔ)言,有些程序員在理解和使用閉包、高階函數(shù)等概念時(shí)總是不能習(xí)慣,這個(gè)問(wèn)題在國(guó)內(nèi)的開(kāi)發(fā)團(tuán)隊(duì)中還挺普遍的。
- 回調(diào)式編程的不習(xí)慣:Node.js 的異步IO 大量依賴回調(diào)?;卣{(diào)讓程序的執(zhí)行出現(xiàn)了兩條路徑,出現(xiàn)故障時(shí)調(diào)用棧也很難理解。這對(duì)習(xí)慣了同步編程的程序員來(lái)說(shuō)一開(kāi)始確實(shí)是個(gè)坎。async, Q promise 等 package 可以緩解這個(gè)問(wèn)題(在 ES6 的Generator 普及之前),不過(guò)這也帶來(lái)了更陡峭的學(xué)習(xí)曲線。一般情況下,需要半年到一年的習(xí)慣過(guò)程,當(dāng)然前提是多看,多寫(xiě)。隨著越來(lái)越多的經(jīng)驗(yàn)分享,這個(gè)過(guò)程也在不斷地縮短。
除此之外的領(lǐng)域,或者沒(méi)有上述問(wèn)題的,都都可以享受到 Node.js 帶來(lái)的生產(chǎn)力提升和穩(wěn)定的性能保障。
性能的爭(zhēng)議
不同開(kāi)發(fā)環(huán)境間的性能對(duì)比從來(lái)都是有爭(zhēng)議的話題。我只能說(shuō),當(dāng)開(kāi)發(fā) Web 或 網(wǎng)絡(luò)環(huán)境下的應(yīng)用時(shí),Node.js 靠以下幾個(gè)方面來(lái)避免出現(xiàn)不必要的性能問(wèn)題:
- Chrome V8,一個(gè)可靠的優(yōu)秀的虛擬機(jī)(hidden classes 和 inline caching),讓 Javascript 的運(yùn)行速度進(jìn)入了第一陣營(yíng)(C++, Java, .NET)。
- 異步 IO 大大降低了線程數(shù)量,莫名其妙的死鎖和等待的概率被降低了很多。大部分場(chǎng)景不用去考慮并發(fā)和同步鎖,犯錯(cuò)誤的機(jī)會(huì)少。而在 Python 中,異步 IO 并不是標(biāo)準(zhǔn),并沒(méi)有被貫穿到所有 Package 中,因此應(yīng)用程序也就很難獲得一致的性能保障。
- 非常輕巧的“內(nèi)核”。Node.js 的模塊分為 Core Modules 和 Userland 兩部分。Core Modules 非常精簡(jiǎn),只包括 TCP, HTTP, DNS, File System, child processes 和其他一些模塊,這些網(wǎng)絡(luò)庫(kù)還只有異步版本。相對(duì)地,在 Userland 中卻有著海量的 Packages。開(kāi)發(fā)應(yīng)用的時(shí)候,我們根據(jù)應(yīng)用的需求來(lái)組合 Userland 的 Packages,使得我們的應(yīng)用程序有機(jī)會(huì)在一個(gè)很低的資源消耗水平下運(yùn)行(在《Announcing ql.io》中指出,一臺(tái)開(kāi)發(fā)服務(wù)器就可以支持 12 萬(wàn)活躍連接,平均每個(gè)連接消耗 2k 內(nèi)存)。事實(shí)上,我開(kāi)發(fā)的 WebSockte 應(yīng)用在 Raspberry Pi 下都可以支持幾百并發(fā)長(zhǎng)連接(WebSocket)。和那些動(dòng)輒上萬(wàn)個(gè)類(lèi)的企業(yè)開(kāi)發(fā)框架相比,這是一個(gè)巨大的優(yōu)勢(shì)。這種方式降低了出現(xiàn)問(wèn)題的概率、查找問(wèn)題的成本以及減少部署成本。
對(duì) Javascript 的絕對(duì)性能的追求一直沒(méi)有停頓(例如, Mozilla 的 asm.js )。而 Node.js 則在絕對(duì)性能的基礎(chǔ)上,確保應(yīng)用程序可以獲得穩(wěn)定和可預(yù)測(cè)的性能保障( Benchmark 和實(shí)際的應(yīng)用運(yùn)行往往是兩回事)。
Node.js繼承了JavaScript 的靈活性,優(yōu)秀的JS庫(kù)應(yīng)當(dāng)如何選擇
可以在 npmjs.org 或者 google 上搜索關(guān)鍵詞。如果類(lèi)似的返回很多,則看其被其他 package 依賴的數(shù)量有多少。上 github 上查看 starred 和 forks 的數(shù)量,讀 issues。
如果是“名人”(substack, visionmedia (TJ Holowaychuk), dominictarr, rvagg 等)寫(xiě)的 Packages 自然會(huì)被加分。
最后是把 Git Repo. Clone 或者 Fork 下來(lái), 閱讀且注釋他們的源代碼。這個(gè)過(guò)程也可以發(fā)現(xiàn)很多他們依賴的其他 Packages。這是一個(gè)蠻享受的過(guò)程,可以學(xué)到很多新知識(shí)和新的用法。
還有一些亂槍打鳥(niǎo)的方法:
- 在 Tweeter 上關(guān)注 @nodenpm,所有在 npm 上發(fā)布或者更新的 packages 都會(huì)在該 handle 上發(fā)布出來(lái)。在你的碎片時(shí)間沒(méi)事可以刷刷這個(gè),當(dāng)然你需要 APN 翻墻。
- 關(guān)注一些推薦和評(píng)論賬號(hào):@dailyjs,@echojs 等。
- Changelog 會(huì)提供不錯(cuò)的開(kāi)源信息匯總,其中包括 Node.js、Javascript 和 npm 欄目。
- Hacker News 則不會(huì)讓你忽略軟件行業(yè)的一些“大事”或者新概念。
一個(gè)項(xiàng)目開(kāi)始前的研究階段,我大約會(huì)瀏覽幾十個(gè) Packages,精讀其中的5 ~ 10個(gè)。開(kāi)發(fā)過(guò)程中則根據(jù)需要還會(huì)不斷地發(fā)現(xiàn)和精讀一些,這些都被我計(jì)入了項(xiàng)目的成本。
"自由選擇,自己負(fù)責(zé)",在這個(gè)龐大的開(kāi)發(fā)社區(qū)了不要指望有人能告訴你“標(biāo)準(zhǔn)答案”。每個(gè)人面臨的問(wèn)題域和知識(shí)背景都不一樣,堅(jiān)持多看,多試,多思考,享受獲得新知識(shí)的過(guò)程比獲得“標(biāo)準(zhǔn)答案”更重要。
在眾多的成熟開(kāi)發(fā)框架下為什么需要Node.js
在每一個(gè)特定的問(wèn)題域,大家總是在嘗試找到最優(yōu)解。這個(gè)過(guò)程是沒(méi)有終結(jié)的,就想最終也會(huì)有其他框架代替 Node.js 一樣。
今天的 Web,是無(wú)數(shù)相互連接的 Web Services 組成的,這些連接的本質(zhì)是異步的。Node.js 天生異步的特性和這個(gè)場(chǎng)景的匹配度相對(duì)其他開(kāi)發(fā)框架要更高,因此實(shí)現(xiàn)起來(lái)也更自然。
除此之外,Node.js 的設(shè)計(jì)基本原則遵循了 《Unix 的編程藝術(shù)》,參見(jiàn) Isaac Z. Schlueter (前任 Node.js 的Gatekeeper,目前負(fù)責(zé) npm 的商業(yè)化) 的Blog: Unix Philosophy and Node.js。
npm 和 stream 就是上述哲學(xué)的產(chǎn)物。
npm
npm 是 Node.js 的包管理系統(tǒng)。包管理系統(tǒng)不是新東西,但是和 npm 的那些前輩和表兄弟不同的是:
- npm 直接集成在 Node.js 中,無(wú)需單獨(dú)安裝,發(fā)布,安裝 packages 非常簡(jiǎn)單。
- npmjs.org 提供一個(gè)統(tǒng)一的入口,你可以看到每個(gè) package 被哪些 packages 所依賴,你也可以一目了然地看到它依賴了誰(shuí),以及最近的下載次數(shù)。結(jié)合到 github 上的更新情況,基本上對(duì)一個(gè) package 的基本情況你都能了解到。
- 約定俗成的發(fā)布規(guī)范:一個(gè) git repo. 讓你可以直接找到源代碼;README.md 提供簡(jiǎn)要的說(shuō)明讓消費(fèi)者能盡快用起來(lái)。
對(duì)于開(kāi)發(fā)者來(lái)說(shuō),每一個(gè) package 就是一個(gè) "micro service",是最小重用單元。大部分的 package 只有幾百行代碼,甚至有些只有幾行代碼。這樣的重用粒度是在其他社區(qū)難以想象的。
在 Node.js 的應(yīng)用的開(kāi)發(fā)過(guò)程中,編寫(xiě) “一口尺寸”(bite-size)的 module 是推薦的編程方式。這也很方便你把這些小 module 封裝為 package 分享到社區(qū)當(dāng)中,而不用擔(dān)心泄露“企業(yè)機(jī)密”。
npm 是每一個(gè) Noder 的 "home",也是每一個(gè) Node.js 應(yīng)用的系統(tǒng)架構(gòu)的一部分。
#p#
Stream
如果說(shuō),npm 提供了“開(kāi)發(fā)時(shí)重用”的機(jī)制,那么 stream 的則提供了“運(yùn)行時(shí)”不同組件之間的“重用”機(jī)制。stream 概念和 unix 中的 stream 對(duì)應(yīng),應(yīng)用中的每一個(gè) component 則對(duì)應(yīng) unix 的 filter。下面舉一個(gè)實(shí)際的例子:
在某個(gè)應(yīng)用中,我需要一個(gè) API Server,它的客戶端包括 Web Browser,iOS App., 以及網(wǎng)絡(luò)中的其他 Server。Web Browser 和我們的 API Server 的通信基于 SockJS(當(dāng)然你也可以選擇 SocketIO,或者 Faye 等),它為瀏覽器兼容提供了適當(dāng)?shù)?“Fallback” 方案;對(duì)于 iOS App.來(lái)說(shuō),由于不需要考慮瀏覽器兼容,則采用基于標(biāo)準(zhǔn)的 RFC 6455 的純 WebSocket 通信協(xié)議,這樣實(shí)現(xiàn)起來(lái)更簡(jiǎn)單;而對(duì)于其他 Server 來(lái)說(shuō),局域網(wǎng)內(nèi)則用 TCP,互聯(lián)網(wǎng)上則用 TLS 來(lái)保證傳輸安全。
我在 Node.js 上是這么實(shí)現(xiàn)的:
- 利用 donde 構(gòu)建一個(gè)通信無(wú)關(guān)的 RPC Server 來(lái)提供 API 服務(wù)。
- 用 Node.js Core Modules 中的 tcp, tls 創(chuàng)建 TCP/TLS Server 并監(jiān)聽(tīng),用第三方的 SockJS 和 websocket-stream 分別創(chuàng)建 SockJS 和 WebSocket 的 Server 并監(jiān)聽(tīng)。
- 當(dāng) Client 連接到不同的端口,在 Server 上就會(huì)創(chuàng)建基于該協(xié)議的 Commnucation Stream,然后創(chuàng)建一個(gè)新的 dnode 實(shí)例,得到一個(gè) dnode 的 Stream。最后將 Commnucation Stream 和 dnode Stream 像接水管一樣接到一起即可。
- net.createServer(function(connStream){
- dnodeStream = dnode({ func1: function(){} });
- connStream.pipe(dnodeStream).pipe connStream;
- });
考慮到在不穩(wěn)定的網(wǎng)絡(luò)環(huán)境下的自動(dòng)重連需求,也可以添加 reconnect。
不算你自己 RPC API 的實(shí)現(xiàn)邏輯,支持這么多的通信協(xié)議的 Server 框架只需要百十行代碼,還加上了一定程度的異常處理。
tcp, tls, SockJS,或者 reconnect 的開(kāi)發(fā)者并不能確定“消費(fèi)者”是如何使用這些 Package 的,但是大家都支持 Stream 的接口,則讓自己的 Package 能夠被運(yùn)用到更多的場(chǎng)景。
進(jìn)一步,我們也可以多路復(fù)用一個(gè)底層的 Stream。我們把上面的例子再擴(kuò)展一下:
在既有的通信連接上(connStream),除了提供 RPC API 之外,還需要添加分布式的狀態(tài)同步功能,例如:通過(guò) Scuttlebutt,完成 Client 與 Server 或 Server 與 Server 之間的常量數(shù)據(jù)自動(dòng)同步,而不用為這些功能設(shè)計(jì)新的 RPC API。通過(guò) mux-demux ,可以復(fù)用既有的網(wǎng)絡(luò)通信 Stream(tcp, SockJS, Web Socket...),避免建立不必要的網(wǎng)絡(luò)連接。
Stream 是 Node.js 的核心概念之一,其接口和工作方式被廣泛地采用,為不同組件在運(yùn)行時(shí)相互通信提供了最基本的支持。
在 Node.js 中,如何使用 Stream 可以用一本書(shū)的容量來(lái)描述,不是因?yàn)?Stream 的概念有多復(fù)雜,而是因?yàn)槠浣M合方式非常豐富。
小結(jié)
三年前接觸 Node.js,并且學(xué)習(xí)和采用,主要原因是因?yàn)?Node.js 在解決當(dāng)今網(wǎng)絡(luò)應(yīng)用的問(wèn)題時(shí),提供了高性能、高可靠和低功耗的方法。高性能、高可靠和低功耗,不是在于 Node.js 做了什么,而是在于 Node.js 不做什么。Node.js 和 Javascript 的概念,在 Java 或者其他開(kāi)發(fā)框架中都能找到對(duì)應(yīng)的概念。但是 Node.js 僅保留了它認(rèn)為最重要的部分作為 Core Modules,其他都讓給了 User Land,這才是高性能、高可靠和低功耗的最本質(zhì)的保障。
隨著 Node.js 這三年的發(fā)展,今天使我浸淫其中的理由已經(jīng)不是之前的那些特點(diǎn)了。
npm 建立了一個(gè)“人人為我,我為人人”社區(qū),無(wú)論你是一個(gè)入門(mén)級(jí)的 Noder,還是一個(gè)多年的老兵,都在自覺(jué)或不自覺(jué)地從這個(gè)社區(qū)吸取營(yíng)養(yǎng),也在不斷地回饋社區(qū)。在使用 npm 的過(guò)程中,你會(huì)很自然地發(fā)現(xiàn),將自己的應(yīng)用切割為盡量小的 Modules,發(fā)布為公有的 Packages,配上一個(gè)簡(jiǎn)單扼要的 README.md,反而是最有效率的系統(tǒng)架構(gòu)方式。
Node.js 所遵循的 Unix 設(shè)計(jì)哲學(xué),又提供了最簡(jiǎn)單有效的復(fù)用規(guī)范。簡(jiǎn)單有效,才會(huì)被大家自覺(jué)采用,采用得越多,重用的可能性就更大。以Express 4.0 ( MEAN 架構(gòu)中的那個(gè) 'E' )為例,這么一個(gè)流行的 MVC Web Framework的核心代碼只有 2,600 多行(不算測(cè)試,中間件和例子,但是包括注釋?zhuān)?/p>
npm 和 github 一起,為今天的軟件生產(chǎn)提供了新的生產(chǎn)關(guān)系,這也是當(dāng)前 Node.js 超越其他社區(qū)的根本原因。不是單純的性能,也不僅僅是因?yàn)閯?dòng)態(tài)語(yǔ)言,甚至不是因?yàn)榇罅渴煜?Javascript 的前端程序員(和后端程序員相比,由于缺少系統(tǒng)性的思維,前端 Javascript 程序員掌握 Node.js 未必有多少優(yōu)勢(shì) ),而是以更加便捷的分享式開(kāi)發(fā)為基礎(chǔ)的生產(chǎn)關(guān)系實(shí)實(shí)在在地提升了軟件生產(chǎn)力。
Node.js的駕馭能力
如果“復(fù)雜的后端程序” 等于 “龐大的繼承樹(shù)”,“強(qiáng)類(lèi)型安全”,“精細(xì)的異常定義和處理”,那么 Node.js 當(dāng)然無(wú)法駕馭。因?yàn)?Node.js 和 Java, .NET 相比,是一顆獨(dú)立的“科技樹(shù)”。原型繼承、函數(shù)式編程、模塊系統(tǒng)、回調(diào)...,這些概念和編程方式對(duì)習(xí)慣了 Java 以及 .NET 的程序員來(lái)說(shuō)不僅僅是不熟悉,甚至一開(kāi)始會(huì)產(chǎn)生“不舒服的”感覺(jué)。
從我的體驗(yàn)來(lái)看(Basic->C->VB->Delphi->.NET->Node.js),這種不舒服更多地來(lái)自于之前對(duì)嚴(yán)謹(jǐn)?shù)念?lèi)型系統(tǒng)的信仰。原本所謂的“架構(gòu)師”,承擔(dān)著整個(gè)應(yīng)用或項(xiàng)目的類(lèi)型系統(tǒng)的建設(shè)任務(wù),對(duì)任何破壞類(lèi)型一致性的行為都會(huì)自然而然的產(chǎn)生抵觸情緒。要想掌握 Node.js,最好的方法是先從 Java, .NET 這顆“科技樹(shù)”上爬下來(lái),清空自己,然后重新爬 Node.js 這棵樹(shù)。
程序員從 Java, .NET 可以學(xué)到面向?qū)ο蠛头盒瓦@些重用手段,而在 Node.js 的世界中,當(dāng)你接觸到大量來(lái)自于完全不同背景的程序員所編寫(xiě)的 Packages 的時(shí)候,你也會(huì)意識(shí)到,不是每樣?xùn)|西都是“類(lèi)”,重用也不一定都基于繼承。雖然有人試圖在 Node.js 中克隆之前自己熟悉的類(lèi)型系統(tǒng),但是更多的程序員則在不斷嘗試更優(yōu)雅、簡(jiǎn)單的編寫(xiě)方式。在 Node.js 的開(kāi)發(fā)過(guò)程中,沒(méi)有所謂的“最佳實(shí)踐”,類(lèi)似的問(wèn)題總會(huì)有人嘗試不同的解決方法。對(duì)于一個(gè)勤于思考和反思的程序員,這是一個(gè)充滿樂(lè)趣的過(guò)程。反之,如果你的團(tuán)隊(duì)是由缺少獨(dú)立思考或者獨(dú)立解決問(wèn)題的程序員組成的,那么 Node.js 確實(shí)不適合。你需要用強(qiáng)類(lèi)型語(yǔ)言搭好一個(gè)受限的框架,然后讓體力型的隊(duì)友去填空。
我們公司只有兩個(gè)程序員,一個(gè)負(fù)責(zé) iOS 開(kāi)發(fā),而我負(fù)責(zé)“復(fù)雜”后端程序和 Web Browser 開(kāi)發(fā)。如果用 Java 或者 .NET 來(lái)開(kāi)發(fā),完成同樣的功能需要至少三倍以上的人力。
Node.js能否統(tǒng)一前后端
完全統(tǒng)一既不可能,也沒(méi)必要。再說(shuō)這個(gè)所謂的“統(tǒng)一”與其放到 Node.js 腦袋上,不如送給 Javascript,因?yàn)?Javascript 用到的場(chǎng)景太多了。讓我們看幾個(gè)事實(shí):
- Node.js 讓我們可以用 Javascript 寫(xiě)后臺(tái)程序
- Node.js 讓我們寫(xiě) Web Browser 前端:一方面,可以通過(guò) Grunt 或者其他持續(xù)集成工具生成可發(fā)布的前端靜態(tài)網(wǎng)站內(nèi)容(例如: Bootstrap); 另一方面,也可以通過(guò) Browserify 在前端代碼中使用 Node.js 的 Modules,讓前后臺(tái)代碼使用統(tǒng)一的代碼基(例如:domready。很多 Node.js 的 Modules 本身就經(jīng)過(guò)了瀏覽器兼容測(cè)試,可以同時(shí)運(yùn)行在兩端)。
- 用 Node.js 開(kāi)發(fā)桌面應(yīng)用,例如:https://github.com/rogerwang/node-webkit/wiki/List-of-apps-and-companies-using-node-webkit,列出了基于 node-webkit 的桌面應(yīng)用列表。
- 即使在性能受限的移動(dòng)設(shè)備中,我們也可以通過(guò) Javascript Binding 將一部分應(yīng)用邏輯用 Javascript 來(lái)實(shí)現(xiàn),而 UI 的渲染還是 Native 的方式。這在很多游戲中已經(jīng)被采用(http://www.zhihu.com/question/21130385)。只要用到 Javascript,或者說(shuō),隨著 Javascript 代碼基的擴(kuò)大,npm based 的包管理方式就會(huì)通過(guò) Browserify 的方式被慢慢引入。
除了第二個(gè)問(wèn)題提到的那些不適合 Node.js 的地方,其他領(lǐng)域想徹底不碰 Node.js 是很難的。
Node.js發(fā)展方向
如果你的老板不讓你碰 Node.js,你需要讓他支付青春損失費(fèi)。開(kāi)個(gè)玩笑:)
投資在 Node.js 不會(huì)吃虧。
基于 Browserify 的貢獻(xiàn),前后臺(tái)一致的代碼基正在成為現(xiàn)實(shí)(在我的一個(gè)項(xiàng)目中已經(jīng)如此,Web Client 通過(guò) Node.js 的 stream 和后端傳遞數(shù)據(jù) )。你可以看到在前端使用原本為后臺(tái)寫(xiě)的Module,或者用寫(xiě)后端程序的方法寫(xiě)前端代碼,例如:domready。瀏覽器中無(wú)需運(yùn)行一個(gè)完整的 Node.js,只要打包好需要的 Modules 下載到瀏覽器執(zhí)行即可。
在問(wèn)題 5 中,大家已經(jīng)看到 Node.js 在分布式計(jì)算領(lǐng)域的應(yīng)用能力。 在問(wèn)題 8 中,大家可以看到 Node.js 在客戶端開(kāi)發(fā)中所扮演的角色。
傳統(tǒng)的數(shù)據(jù)庫(kù)這一領(lǐng)域也在發(fā)生變化。通用的數(shù)據(jù)庫(kù)系統(tǒng)在未來(lái)會(huì)慢慢“失寵”,“樂(lè)高積木”化的存儲(chǔ)服務(wù)會(huì)流行起來(lái)。Hackers 們圍繞著 LevelUp構(gòu)建自己的存儲(chǔ)引擎,從 key/value,到Graph DB;從基于 B 樹(shù)的一維索引到基于 R-Tree 的多維索引;從能夠在瀏覽器中運(yùn)行的嵌入數(shù)據(jù)庫(kù)到支持成千上萬(wàn)訪問(wèn)者,高可用的數(shù)據(jù)庫(kù)系統(tǒng);從支持兩階段提交的 Transaction 到,到支持實(shí)時(shí)增量的 Map-Reduce。在我的一個(gè)項(xiàng)目中已經(jīng)開(kāi)始采用這種方法,為特定的存儲(chǔ)和查詢需求構(gòu)建特定的存儲(chǔ)服務(wù)。這在以前是不可想象的,但是現(xiàn)在,也就是一個(gè)程序員的工作吧。
我是一個(gè)自己寫(xiě)程序的“產(chǎn)品經(jīng)理”。每年有8個(gè)月是集中開(kāi)發(fā)的時(shí)間,剩下的時(shí)間則是負(fù)責(zé)產(chǎn)品設(shè)計(jì)。關(guān)注的方向從 Web、Mobile App. 到后端系統(tǒng)。Node.js 給我提供了無(wú)數(shù)塊“樂(lè)高積木”,讓我可以拼裝自己的玩具,這是很快樂(lè)的體驗(yàn)的過(guò)程。遺憾的就是時(shí)間不夠多,有那么多東西沒(méi)時(shí)間去了解,去體會(huì)其他人的奇思妙想。小公司也是對(duì)成本極度敏感的,如果沒(méi)有 Node.js 很多東西連想都不敢想。




























