首先咱們來思考一個問題:咱們都知道幾乎全部現代主流瀏覽器都全面支持了ECMAScript 5.1版標準,而JavaScript的標準是ECMAScript。那麼咱們就容易認爲JavaScript是一種瀏覽器端的解釋型編程腳本。那麼脫離了瀏覽器,JavaScript還可以解釋運行嗎? 答案是確定的,也就是說脫離了瀏覽器,在特定環境下JavaScript仍是能運行的。JavaScript向來以Web網頁的腳本語言而著稱,但如今也能夠用在許多非瀏覽器環境,例如node.js或者Apache CouchDB。本文就是基於NodeJS來進行探討。前端
根據百度百科解釋,Node.js是一套用來編寫高性能網絡服務器的JavaScript工具包。Node.js是一個能夠快速構建網絡服務及應用的平臺,該平臺的構建是基於Chrome's JavaScript runtime,也就是說,實際上它是對GoogleV8引擎(應用於Google Chrome瀏覽器)進行了封裝。V8引 擎執行Javascript的速度很是快,性能很是好。node
NodeJS並非提供簡單的封裝,而後提供API調用,若是是這樣的話那麼它就不會有如今這麼火了。Node對一些特殊用例進行了優化,提供了替代的API,使得V8在非瀏覽器環境下運行得更好。例如,在服務器環境中,處理二進制數據一般是必不可少的,但Javascript對此支持不足,所以,V8.Node增長了Buffer類,方便而且高效地 處理二進制數據。所以,Node不只僅簡單的使用了V8,還對其進行了優化,使其在各環境下更加給力。web
一、基於V8虛擬機,可構建高性能服務器數據庫
V8引擎自己使用了一些最新的編譯技術。這使得用Javascript這類腳本語言編寫出來的代碼與用C這類高級語言寫出來的代碼性能相差無幾,卻節省了開發成本。對性能的苛求是Node的一個關鍵因素。 Javascript是一個事件驅動語言,Node利用了這個優勢,編寫出可擴展性高的服務器。Node採用了一個稱爲「事件循環(event loop)」的架構,使得編寫可擴展性高的服務器變得既容易又安全。提升服務器性能的技巧有多種多樣。Node選擇了一種既能提升性能,又能減低開發複雜度的架構。這是一個很是重要的特性。併發編程一般很複雜且佈滿地雷。Node繞過了這些,但仍提供很好的性能。apache
二、單線程編程
Node.js能夠在不新增額外線程的狀況下,依然能夠對任務進行並行處理 —— Node.js是單線程的。它經過事件輪詢(event loop)來實現並行操做,對此,咱們應該要充分利用這一點 —— 儘量的避免阻塞操做,取而代之,多使用非阻塞操做。後端
三、可利用Javascript進行後臺開發瀏覽器
雖然讓Javascript運行於服務器端不是Node的獨特之處,但倒是其一強大功能。不得不認可,瀏覽器環境限制了咱們選擇編程語言的自由。任何服務器與日益複雜的瀏覽器客戶端應用程序間共享代碼的願望只能經過Javascript來實現。雖然還存在其餘一些支持Javascript在服務器端 運行的平臺,但由於上述特性,Node發展迅猛,成爲事實上的平臺。安全
四、非阻塞IO服務器
Node採用一系列「非阻塞」庫來支持事件循環的方式。本質上就是爲文件系統、數據庫之類的資源提供接口。向文件系統發送一個請求時,無需等待硬盤(尋址並檢索文件),硬盤準備好的時候非阻塞接口會通知Node。該模型以可擴展的方式簡化了對慢資源的訪問, 直觀,易懂。尤爲是對於熟悉onmouseover、onclick等DOM事件的用戶,更有一種似曾相識的感受。
五、RESTFUL API
本人如今在IBM公司實習,參與公司雲辦公系統的項目研發,本人所在項目組主要負責在線電子表格的開發工做。項目前端開發是基於DOJO框架,後臺主要基於JAVA。項目功能性開發已經基本完成,可是在實際測試階段發如今編輯超過必定閾值的大數據的狀況下系統開銷比較大,運行效率沒法知足要求。
在通過大量跟蹤測試及分析後,基於系統的總體架構以及解決該性能問題,咱們有兩套解決方案:一、因爲如今系統詞法解析採用的是開源語法分析器ANTLR,而ANTLR在效率上還略有不足,所以咱們決定基於ANTLR來進行二次開發,尋求一些改進;二、創建前端服務器,和後臺服務器進行分離。前端與後臺共同維護一致的數據模型,前端服務器主要解決運算方面的請求並將計算結果及時反饋用戶,而後將改變發送到後臺服務器,由後臺服務器進行持久化存盤、消息分發等一些操做。
因爲前端是基於DOJO框架進行的開發,爲了最大限度的重用前階段實現的功能代碼來咱們考慮基於NodeJS來搭建前端服務器,並充分利用NodeJS的一些特性來實現系統性能的提升。
我想不只僅是Node.js,當咱們要引入任何一種新技術前都必需要搞清楚幾個問題:
Server端阻塞是當前系統遇到的最大問題。在整個數據查詢的過程當中,當前程序進程每每只是在等待結果的返回,這就形成了進程的阻塞。對於高併發、計算任務較大以及I/O密集行的網絡應用中,一方面進程很長時間處於等待狀態,另外一方面爲了應付新的請求不斷的增長新的進程。這樣的浪費會致使系統支持QPS遠遠小於後端數據服務可以支撐的QPS,成爲了系統的瓶頸。Node一貫是這樣來標榜本身的:「在node中除了代碼,全部一切都是並行執行的」。這句話的意思是說,Node.js能夠在不新增額外線程的狀況下,依然能夠對任務進行並行處理 。Node.js是單線程的,它經過事件輪詢(event loop)來實現並行操做,對此,咱們應該要充分利用這一點 ,儘量的避免阻塞操做,取而代之,多使用非阻塞操做。咱們搭建前端服務器主要用於處理前端大量的公司計算並將計算結果及時呈現給用戶,因此可以避免不少I/O阻塞操做,這樣就能充分利用NodeJS的優勢同時也可以知足咱們的需求。另外,咱們前端基於的DOJO框架是基於JS的,而NodeJS在處理JavaScript的優點在前面已有介紹,這裏再也不贅述。
解決阻塞能夠引入事件處理機制解決這個問題,在查詢請求發起以前註冊數據加載事件的響應函數,請求發出以後當即將進程交出,而當數據返回後再觸發這個事件並在預約好的事件響應函數中繼續處理數據。而JavaScript,相對於其餘語言,至少有兩個關鍵特性決定它特別適合完成這個任務。
(一) JavaScript是一種函數式編程語言,函數編程語言最重要的數學基礎是λ演算(lambda calculus) ,即函數對象能夠做爲其餘函數對象的輸入(參數)和輸出(返回值)。這個特性使得爲事件指定回調函數變得很容易。特別是JavaScript還支持匿名函數,經過匿名函數的輔助,咱們很容易實現回調。(二)JavaScript的另一個重要語言特性:閉包(Closures)。該特性可使異步回調的運行上下文保持,即"狀態保持"。
阻塞式編程浪費了大量進程資源只是在等待,致使大量內存和cpu的浪費。在這方面Node.js好不少,但也正是由於一些閉包等JavaScript內建機制也會致使資源的浪費。看下面的代碼:
Js代碼:
1 function main(){ 2 var id = "1"; 3 var str = "..."; //這裏局部變量str存儲一個2M的字符串 4 db.query("selcect name from persons where id=" + id,function(name){ 5 output("person id:" + id + ", name:" + name);//n秒後數據返回後執行回調 6 }); 7 } 8 main();
至少整個數據查詢過程當中,變量str所使用的2M內存並不會被釋放,而str保持下去可能並無意義。前面已經解釋過閉包的原理,閉包並無智能到只包起來從此可能被訪問到的對象。