一、特點(diǎn)
作為后端JavaScript的運(yùn)行平臺(tái),Node保留了前端瀏覽器JavaScript中那些熟悉的接口,沒(méi)有改寫(xiě)語(yǔ)言本身的任何特性,依舊基于作用域和原型鏈,區(qū)別在于它將前端中廣泛運(yùn)用的思想遷移到了服務(wù)器端。Node相較于其他語(yǔ)言的特點(diǎn)如下所示:
1、異步I/O
在Node中,絕大多數(shù)的操作都以異步的方式進(jìn)行調(diào)用。Ryan Dahl排除萬(wàn)難,在底層構(gòu)建了很多異步I/O的API,從文件讀取到網(wǎng)絡(luò)請(qǐng)求等,均是如此。這樣的意義在于,在Node中,我們可 以從語(yǔ)言層面很自然地進(jìn)行并行I/O操作。每個(gè)調(diào)用之間無(wú)須等待之前的I/O調(diào)用結(jié)束。在編程模型上可以極大提升效率。
以同時(shí)執(zhí)行兩個(gè)文件讀取任務(wù)為例,異步I/O取決于最慢的那個(gè)文件讀取的耗時(shí),而同步I/O的耗時(shí)是兩個(gè)任務(wù)的耗時(shí)之和。這里異步帶來(lái)的優(yōu)勢(shì)是顯而易見(jiàn)的。
2、事件
隨著Web 2.0時(shí)代的到來(lái),JavaScript在前端擔(dān)任了更多的職責(zé),事件也得到了廣泛的應(yīng)用。 Node不像Rhino那樣受Java的影響很大,而是將前端瀏覽器中應(yīng)用廣泛且成熟的事件引入后端, 配合異步I/O,將事件點(diǎn)暴露給業(yè)務(wù)邏輯。
事件的編程方式具有輕量級(jí)、松耦合、只關(guān)注事務(wù)點(diǎn)等優(yōu)勢(shì),但是在多個(gè)異步任務(wù)的場(chǎng)景下,事件與事件之間各自獨(dú)立,如何協(xié)作是一個(gè)問(wèn)題。
3、回調(diào)函數(shù)
與其他的Web后端編程語(yǔ)言相比,Node除了異步和事件外,回調(diào)函數(shù)是一大特色?v觀(guān)下來(lái),回調(diào)函數(shù)也是最好的接受異步調(diào)用返回?cái)?shù)據(jù)的方式。但是這種編程方式對(duì)于很多習(xí)慣同步思路編程的人來(lái)說(shuō),也許是十分不習(xí)慣的。代碼的編寫(xiě)順序與執(zhí)行順序并無(wú)關(guān)系,這對(duì)他們可能造成閱讀上的障礙。在流程控制方面,因?yàn)榇┎辶水惒椒椒ê突卣{(diào)函數(shù),與常規(guī)的同步方式相比,變得不那么一目了然了。
4、單線(xiàn)程
JavaScript語(yǔ)言的一大特點(diǎn)就是單線(xiàn)程,也就是說(shuō),同一個(gè)時(shí)間只能做一件事。JavaScript的單線(xiàn)程,與它的用途有關(guān)。作為瀏覽器腳本語(yǔ)言,JavaScript的主要用途是與用戶(hù)互動(dòng),以及操作DOM。這決定了它只能是單線(xiàn)程,否則會(huì)帶來(lái)很復(fù)雜的同步問(wèn)題。比如,假定JavaScript同時(shí)有兩個(gè)線(xiàn)程,一個(gè)線(xiàn)程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容,另一個(gè)線(xiàn)程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個(gè)線(xiàn)程為準(zhǔn)?所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線(xiàn)程,這已經(jīng)成了這門(mén)語(yǔ)言的核心特征。
Node保持了JavaScript在瀏覽器中單線(xiàn)程的特點(diǎn)。而且在Node中,JavaScript與其余線(xiàn)程是無(wú)法共享任何狀態(tài)的。單線(xiàn)程的最大好處是不用像多線(xiàn)程編程那樣處處在意狀態(tài)的同步問(wèn)題,這里沒(méi)有死鎖的存在,也沒(méi)有線(xiàn)程上下文交換所帶來(lái)的性能上的開(kāi)銷(xiāo)。
同樣,單線(xiàn)程也有它自身的弱點(diǎn),具體有以下3方面:無(wú)法利用多核CPU;錯(cuò)誤會(huì)引起整個(gè)應(yīng)用退出,應(yīng)用的健壯性值得考驗(yàn);大量計(jì)算占用CPU導(dǎo)致無(wú)法繼續(xù)調(diào)用異步I/O。
像瀏覽器中JavaScript與UI共用一個(gè)線(xiàn)程一樣,JavaScript長(zhǎng)時(shí)間執(zhí)行會(huì)導(dǎo)致UI的渲染和響應(yīng)被中斷。在Node中,長(zhǎng)時(shí)間的CPU占用也會(huì)導(dǎo)致后續(xù)的異步I/O發(fā)不出調(diào)用,已完成的異步I/O的回調(diào)函數(shù)也會(huì)得不到及時(shí)執(zhí)行。
HTML5定制了Web Workers的標(biāo)準(zhǔn),Web Workers能夠創(chuàng)建工作線(xiàn)程來(lái)進(jìn)行計(jì)算,以解決JavaScript大計(jì)算阻塞UI渲染的問(wèn)題。工作線(xiàn)程為了不阻塞主線(xiàn)程,通過(guò)消息傳遞的方式來(lái)傳遞運(yùn)行結(jié)果,這也使得工作線(xiàn)程不能訪(fǎng)問(wèn)到主線(xiàn)程中的UI。
Node采用了與Web Workers相同的思路來(lái)解決單線(xiàn)程中大計(jì)算量的問(wèn)題:child_process。 子進(jìn)程的出現(xiàn),意味著Node可以從容地應(yīng)對(duì)單線(xiàn)程在健壯性和無(wú)法利用多核CPU方面的問(wèn)題。通過(guò)將計(jì)算分發(fā)到各個(gè)子進(jìn)程,可以將大量計(jì)算分解掉,然后再通過(guò)進(jìn)程之間的事件消息來(lái)傳遞結(jié)果,這可以很好地保持應(yīng)用模型的簡(jiǎn)單和低依賴(lài)。通過(guò)Master-Worker的管理方式,也可以很好地管理各個(gè)工作進(jìn)程,以達(dá)到更高的健壯性。
二、應(yīng)用場(chǎng)景
在進(jìn)行技術(shù)選型之前,需要了解一項(xiàng)新技術(shù)具體適合什么樣的場(chǎng)景,畢竟合適的技術(shù)用在合適的場(chǎng)景可以起到意想不到的效果。關(guān)于Node,探討得較多的主要有I/O密集型和CPU密集型。
1、I/O密集型
如果將所有的腳本語(yǔ)言拿到一處來(lái)評(píng)判,那么從單線(xiàn)程的角度來(lái)說(shuō),Node處理I/O的能力是值得豎起拇指稱(chēng)贊的。通常, 說(shuō)Node擅長(zhǎng)I/O密集型的應(yīng)用場(chǎng)景基本上是沒(méi)人反對(duì)的。Node面向網(wǎng)絡(luò)且擅長(zhǎng)并行I/O,能夠有效地組織起更多的硬件資源,從而提供更多好的服務(wù)。
I/O密集的優(yōu)勢(shì)主要在于Node利用事件循環(huán)的處理能力,而不是啟動(dòng)每一個(gè)線(xiàn)程為每一個(gè)請(qǐng)求服務(wù),資源占用極少
2、CPU密集型
換一個(gè)角度,在CPU密集的應(yīng)用場(chǎng)景中,Node是否能勝任呢?實(shí)際上,V8的執(zhí)行效率是十分高的。單以執(zhí)行效率來(lái)做評(píng)判,V8的執(zhí)行效率是毋庸置疑的。
CPU密集型應(yīng)用給Node帶來(lái)的挑戰(zhàn)主要是:由于JavaScript單線(xiàn)程的原因,如果有長(zhǎng)時(shí)間運(yùn)行的計(jì)算(比如大循環(huán)),將會(huì)導(dǎo)致CPU時(shí)間片不能釋放,使得后續(xù)I/O無(wú)法發(fā)起。但是適當(dāng)調(diào)整和分解大型運(yùn)算任務(wù)為多個(gè)小任務(wù),使得運(yùn)算能夠適時(shí)釋放,不阻塞I/O調(diào)用的發(fā)起,這樣既可同時(shí)享受到并行異步I/O的好處,又能充分利用CPU。
掃一掃 加微信咨詢(xún)