首先介紹下什麼是nodejavascript
1,單線程前端
node保持了javascript在瀏覽器中單線程的特色,Node中,Javascript與其他線程沒法共享任何狀態。java
單線程好處:不用到處在乎狀態的同步,沒有死鎖,也沒有線程上下文切換帶來的性能開銷。node
單線程壞處:沒法利用多核cpu,錯誤會引發整個應用退出,應用的健壯性值得考驗,大量計算佔用CPU沒法繼續調用異步I/O。git
(注意:針對這些單線程壞處,node都有解決方案,這裏不談)es6
2,跨平臺 (基於libuv)github
兼容Windows和*nix平臺主要得益於Node在架構層的的改動,它在操做系統與Node與操做系統之間構建了一層平臺層框架,即libuv。目前,libuv已是許多系統實現跨平臺的基礎組件。web
經過良好的架構,Node的第三方C++模塊也能夠藉助libuv實現跨平臺,目前,除了沒有保持更新的C++模塊外,大部分C++模塊都能實現跨平臺的兼容。apache
Java有類文件,Python有import機制,Ruby有require,PHP有include和require。瀏覽器端Javascript是沒有標準的模塊機制的,只能經過<script>標籤引入代碼顯得雜亂無章,npm
語言自己沒有組織和約束能力,開發者不得不經過命名空間等方式人爲約束代碼。-》AMD,CMD。
CommonJS規範:但願javascript可以在任何地方運行。
CommonJS的規範提出主要是爲了彌補當前Javascript沒有標準的缺陷,以達到像Python,Ruby和Java具有開發大型應用的基礎能力,而不是停留在小腳本程序的階段.NodeJS是這種規範的實現
CommonJS規範涵蓋了模塊,二進制,Buffer,字符集編碼,I/O流,進程環境,文件系統,套接字,單元測試,Web服務網管接口,包管理等。
CommonJS有不少實現,其中不乏不少大名鼎鼎的項目,好比 說:Apache的CouchDB和node.js等。但這些項目大 部分只實現了CommonJS的部分規範。具體的項目和實現部分參見官方網站的說 明:http://commonjs.org/impl/
Node模塊實現
4,應用場景
I/O密集型
是否不擅長cpu密集型?
但凡這種「既是單線程又是異步」的語言有一個共同特色:它們是 event-driven 的。驅動它們的 event 來自一個異構的平臺。
異步調用(封裝參數)-》線程池(iocp)-》事件循環(監聽者-》執行回調函數)
[注]:操做系統對計算機進行了抽象,將全部輸入輸出設備抽象爲文件,內核在進行文件I/O操做時,經過文件描述符進行管理,而文件描述符相似於應用程序與系統內核
之間的憑證。應用程序若是須要進行I/O調用,須要先打開文件描述符,而後根據文件描述符去實現文件的數據讀寫。此處阻塞/O與非阻塞I/O的區別在於阻塞I/O完成整個獲取
數據的過程,而非阻塞I/O則不帶數據直接返回,要獲取數據,還須要經過文件描述符再次讀取。
阻塞I/O的一個特色是必定要等待系統內核層面完成全部數據操做後,調用才結束。以讀取磁盤文件爲例:系統內核在完成磁盤尋道,讀取數據,複製數據到內存中以後這個調
用才結束。如圖:
阻塞I/O形成了CPU等待,浪費了等待時間,CPU的處理能力不能獲得充分利用。爲了提升性能,內核提升了非阻塞I/O。非阻塞I/O跟阻塞I/O的區別爲調用以後當即返回,如圖:
非阻塞I/O返回以後,CPU的時間片能夠用來處理其餘事務,此時性能提高是明顯的。
但非阻塞I/O也存在一些問題。因爲完整的I/O沒有完成,當即返回並非業務層指望的數據,而僅僅是打當前調用的狀態,爲了獲取完整的數據,應用層序須要重複調用I/O操做來
確認是否完成。這種重複的調用判斷操做是否完成的技術叫作輪詢。[注]:任意技術都並不是是完美的,阻塞I/O形成CPU等待浪費,非阻塞I/O帶來的麻煩倒是須要輪詢取確認是否
徹底完成數據獲取,他會讓CPU處理狀態判斷,是對CPU的資源浪費。
輪詢技術是有演進的,以減小I/O狀態判斷的CPU損耗。從read->select->poll->epoll。具體狀況這裏不談。
理想的非阻塞異步I/O:咱們指望的完美的異步I/O應該是應用程序發起非阻塞調用,無需經過遍歷或者事件喚醒燈方式輪詢,能夠直接處理下一個任務,只須要在I/O完成後經過信號
或者回調函數講數據傳遞給應用程序便可,以下圖:
幸運的是,在Linux中存在這中方式,它提供一個異步的I/O方式(AIO)就是經過信號或回調來傳遞數據的。但不幸的是,只有Linux中有,而且AIO只支持內核I/O中的O_DIRECT方法
讀取,而且沒法利用系統緩存。
現實確定比理想要骨感一些,可是要達成異步I/O的目標,也並不是難事。前面咱們講場景都限定在單線程的狀態下,多線程的方式就是另外一番風景了。經過讓部分線程進行阻塞I/O
或者非阻塞I/O加輪詢技術來完成數據獲取,讓一個線程進行計算,經過線程之間的同窗講I/O獲得數據進行傳遞,這就輕鬆實現了異步I/O(儘管是模擬的)。
[注]:這裏的I/O不只僅只侷限於磁盤讀寫*nix將計算機抽象了一番,磁盤文件,硬件,套接字等幾乎全部計算機資源都被抽象成了文件,所以這裏的描述的阻塞和非阻塞的狀況
一樣適合套接字等。
[注]:咱們雖然時常提到Node是單線程的,這裏的單線程僅僅指的是Javascript執行在但造成中罷了。在Node中,不管是什麼平臺,內部完成的I/O任務都是另有線程池的。
3,爲何要用異步?
Deferred是前端解決異步操做的一種編程範式,後來出現的Promise規範更是讓其普適性大大提升。不過Promise規範也存在分岐。如今最流行的是Promise/A+規範。
一個兼容 ES6 Promises 的Polyfill類庫。 它基於 RSVP.js 這個兼容 Promises/A+ 的類庫, 它只是 RSVP.js 的一個子集,只實現了Promises 規定的 API。
這是一個獨立版本的 YUI 的 Promise Polyfill,具備和 ES6 Promises 的兼容性。
Promise
擴展類庫 使用過Node.js的人可能會知道Q
模塊,Q
實現了Promises
和 Deferreds
等規範,在Node.js中環境或瀏覽器環境中使用。
一個Promise/A+
簡單實現模塊,除實現then
方法外,還擴展一些標準外的方法,在Node.js中環境或瀏覽器環境中使用。
bluebird
類庫除了兼容Promise
規範以外,還對Promise
對象進行了必定的擴展,如:取消promise對象的運行等。另外,還在運行效率上進行了必定的優化。bluebird
也是一 個npm
模塊,能夠在Node.js中環境或瀏覽器環境中使用。
其餘
《深刻淺出node》做者樸靈寫的
EventProxy參考:
https://github.com/JacksonTian/eventproxy
Wind.js https://github.com/JeffreyZhao/wind http://blog.fens.me/nodejs-async-windjs/