NodeJS學習筆記(一)——異步I/O的理解

寫在開篇的題外話一個偶然的機會讓我接觸到了前端開發的相關知識,從此以後就陷入了前端開發的懷抱,無法自拔。在做完一個又一個項目之後,才知道前後端的“戀愛”有多麼痛苦,欲分不分的藕斷絲連讓其他開發者頭疼不已。在學習了NodeJS的一些知識後,才發現這簡直就是解救前端開發人員的利器啊!遂開始學習,在此記錄下學習心得,如有理解的不正確的地方,還希望批評指正。

Node是什麼

在剛接觸並提起Node.js時被人問到最多的一個問題就是:這到底是個什麼東西?最初我理解Node是一個前端的服務器,類似我們常用的tomcat、apache等,然而這個理解是錯的。Node只是一個Javascript運行平臺而已。

最初的Javascript只是基於網頁的小腳本,要依賴web應用環境纔可以運行。然而Node的出現讓我們可以像Java一樣,編寫系統級、服務端的代碼,並在Node平臺上直接運行。然而單純使用Node作爲服務器的底層又不是很現實,使用它作爲前端的服務器再合適不過了,這樣前端和後端可以更好的進行分離,底層接口提供合適的數據結構,交給前端,前端可以自己構建高效率、可用性高的接口,只要接口之間的數據結構不發生變化,前後臺之間是不會造成任何影響的。

從異步I/O說起

Node的高性能是離不開異步I/O的,那麼我們就從異步I/O開始理解一下Node的工作機制。

第一段Node代碼從Hello World開始


Node的模塊機制——彌補javascript先天對模塊功能的欠缺

在以上的例子中,我們創建了一個服務,監聽了8686端口。在監聽到8686端口請求之後,調用了函數fInitServer,fInitServer方法是針對用戶請求連接事件的函數。這個服務中傳入的參數爲webrequestresponse在回調函數中,執行了請求連接後服務器的響應,即通過response瀏覽器輸出Hello World字符串

var http = require(‘http’);

這句代碼引入了Node核心的http模塊Node引入了一部分CommonJS規範,使用require引入模塊。Node引入模塊的流程爲:

分析路徑->查找文件->編譯執行

Node的模塊分爲兩類:核心模塊和文件模塊。

核心模塊是Node提供的模塊,核心模塊已經被編譯過,它在Node進程啓動時就被加載到內存中,所以在引用核心模塊時,不需要進行路徑的分析和源文件的查找,並優先判斷,使用核心模塊的效率是很高的。

文件模塊是用戶自定義開發的模塊,在引入用戶自定義模塊時,首先要根據require傳入的路徑(可以是相對路徑,也可以是絕對路徑)進行解析,定位到模塊源文件,並對源文件進行擴展名分析等操作後,對模塊進行編譯,再將模塊放到緩存中,方便下次使用。由於Node查找自定義模塊路徑是逐級向上遞歸查找的,所以文件路徑越深,查找耗時會越多,所以在引入自定義模塊時路徑要儘量精確。

提示:在使用node的express框架,運行js可能會遇到這個問題:cannot find module “express”。由Node加載模塊的原理可以看出,出現這個錯誤的原因是沒有在工程路徑下安裝express模塊,Node執行時會遞歸查找node_modules目錄,如果找不到則會報無法找到模塊的問題。

異步I/O的實現

Node是如何在用戶請求後,調用fInitServer函數的呢?

操作系統對I/O的操作分爲阻塞I/O和非阻塞I/O阻塞I/O造成了CPU的等待,使CPU不能得到充分的利用;而非阻塞I/O雖然不必等待完整I/O的返回,但需要通過輪詢重複的調用判斷操作,這種判斷操作也是對CPU的一種浪費。我們希望非阻塞I/O可以免去輪詢的步驟,在實際I/O操作完成後,通過返回完成信號通知應用程序即可。

Node使用了觀察者模式和事件循環機制來實現這種異步I/O這裏以去餐廳消費爲例,異步調用相當於去餐廳就餐的顧客,顧客將菜單交給服務員,即NodeI/O觀察者,廚房即Node的事件循環機制詢問服務員是否還有要做的菜,服務員將顧客的菜單交給廚房處理。


Node有自身的事件循環機制,從I/O觀察中取得是否還有待執行的事件,如果有事件,調用對應的I/O線程執行,這時會生產一個請求對象,這個請求對象記錄了提交I/O的狀態、記錄了事件的回調等信息,在I/O線程執行完畢後,會修改請求對象的執行狀態,並通知事件循環系統,將處理完成的I/O信息通知I/O觀察者,執行回調函數。

從上述流程可以看出,Node是以事件爲驅動來實現異步I/O

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章