前言
本來開始寫博客的時候只是想寫一下關於MongoDB的使用總結的,后來覺得還不如干脆寫一個node項目實戰教程實戰。寫教程一方面在自己寫的過程中需要考慮更多的東西,另一方面希望能對node入門者有一些幫助。相信大多數跟隨前面一章教程來到這一章的讀者大多分成兩類,第一類是知道node,想學習node,但是英文匱乏或者網上教程不給力,希望有一個全面一點的教程入門的;第二類應該是node入門,但是之前使用的不是類似MongoDB這種非關系型數據庫,想學習一下的。從我個人的角度看來,我希望自己前一段時間關於前端和后端的協同開發經驗能夠得到提煉和分享。
Nodejs簡介
Node.js
是一個基於Chrome JavaScript
運行時建立的一個平台,用來方便地搭建快速的 易於擴展的網絡應用。Node.js
借助事件驅動, 非阻塞I/O
模型變得輕量和高效,非常適合 運行在分布式設備的數據密集型的實時應用。--百度百科
對於不熟悉JavaScript
的讀者來說,上面的概念可能並不是很親切,但其實,node作為一個平台,他的很多特性基本上就是JavaScript
本身的特性。本文假設你對JavaScript有一定的了解,對於上面的概念給出本人自己的解釋。
我想首先介紹一下宿主環境這個概念。一門語言在運行的時候,需要一個環境,叫做宿主環境。對於JavaScript,宿主環境最常見的是web瀏覽器,瀏覽器提供了一個JavaScript運行的環境,這個環境里面,需要提供一些接口,好讓JavaScript引擎能夠和宿主環境對接。JavaScript引擎才是真正執行JavaScript代碼的地方,常見的引擎有V8(目前最快JavaScript引擎、Google生產)、JavaScript core。JavaScript引擎主要做了下面幾件事情:(1)一套與宿主環境相聯系的規則;(2)JavaScript引擎內核(基本語法規范、邏輯、命令和算法);(3)一組內置對象和API;(4)其他約定。 但是環境不是唯一的,也就是JavaScript不僅僅能夠在瀏覽器里面跑,也能在其他提供了宿主環境的程序里面跑,最常見的就是nodejs。同樣作為一個宿主環境,nodejs也有自己的JavaScript引擎--V8。根據官方的定義 Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications -- 來自我的博客 《JavaScript中的this陷阱的最全收集--沒有之一》
因此我們可以這么理解node
,它不是一門語言,而是一個平台。node
是JavaScript運行的一個宿主環境,它提供了一些接口,能夠讓JavaScript引擎與這個宿主環境對接。真正執行JavaScript代碼的是JavaScript引擎,也就是V8引擎,這個引擎值Google生產的,是當前最快的JavaScript引擎,沒有之一。
Nodejs特性解析
到現在為止我們就知道了Nodejs
的真面貌,但是還不清楚它的幾個特點。Nodejs
的這些特點,也可以說是JavaScript
的特點,畢竟Nodejs
只是一個平台,而執行的代碼,都是JavaScript
代碼。所以我斗膽嘗試解釋JavaScript/Nodejs
的這幾個特點,如有錯誤,非常歡迎指出。
-
同步與異步
在JavaScript
里面的調用分成兩種,一種是同步調用,一種是異步調用。簡單的區別就是,調用的時候能夠立馬得到結果的就是同步調用,不能立馬得到結果的就是異步調用。同步非常好理解,一個簡單的數學運算就是同步調用。異步的話,可以舉一個常見的例子,一篇文章可能有很多很多評論,在頁面加載好的時候,只顯示前面幾條,如果用戶想查看更多,就會點擊加載更過評論按鈕。為了提高用戶體驗,通常是發送Ajax請求,獲取更多內容。這個請求並不能立馬得到回應,而是等待數據返回。等數據返回之后,再動態加載到頁面中,這就是異步調用。 -
單線程與Event Loop
為了要弄清楚事件驅動與非阻塞I/O,我們需要大概了解JavaScript運行的時候的原理。也就需要知道單線程和Event Loop這兩個概念。什么是單線程呢?我們知道線程是CPU調度的基本單位,單線程意味着JavaScript線程在某一個時刻只能執行一個調用。剛剛又說了,調用分成同步調用和異步調用,這兩者的區別決定了在執行JavaScript代碼的時候,總是先執行完所有同步代碼,再去查看是否有異步調用需要執行。這個原理其實就是JavaScript事件驅動的底層原理--Event Loop
。再具體闡述什么是Event Loop之前,我先借用一張好圖:
我們可以看到,在JavaScript
執行棧中,總是先把所有的調用推入棧中,如果遇到了異步調用,就會放到WebAPIs
中,然后繼續執行后面的代碼,等到WebAPIs
中的異步調用執行完成后,不是立馬執行,而是先放到callback queue
里面,那么這個隊列里面的函數怎么執行?什么時候執行?中介者就是Event Loop
了,他會一直詢問callback queue
里面有無需要執行的代碼,如果有,推送到執行棧的最后面,等待執行。如果執行棧中沒有同步代碼在執行,就會立即執行這個這個回調。拿我們平常寫JavaScript
常見的綁定事件處理程序來講,屬於DOM
事件,如果產生了DOM
事件,比如點擊鼠標,那么這個時候就會放到callback queue
里,Event Loop
的下一次詢問,就會放到執行棧里面。通常執行棧里面的同步代碼是很少的,所以通常這個點擊后的事件立馬就執行了。
以上就是Event Loop
的大致解析。如果想要更加深入理解Event Loop
,可以看看我之前寫過的一篇博客《JavaScript的計時器的工作原理》,當然更加推薦大家看看Philip Roberts
大神的演講《Help, I'm stuck in an event-loop》不過可能需要翻牆或者代理。 -
非阻塞I/O與事件驅動
如果你理解了剛剛的Event Loop
,應該就明白了什么叫非阻塞I/O
和事件驅動了。首先還是講講什么是非阻塞I/O
。
線程在執行中如果遇到磁盤讀寫或網絡通信(統稱為
I/O
操作),通常要耗費較長的時間,這時操作系統會剝奪這個線程的CPU控制權,使其暫停執行,同時將 資源讓給其他的工作線程,這種線程調度方式稱為阻塞。當I/O
操作完畢,操作系統將這個線程的阻塞狀態解除,恢復其對CPU
的控制權,令其繼續執行。這種I/O
模式就是通常的同步式I/O(Synchronous I/O)
.
當線程遇到I/O
操作時,不會以阻塞的方式等待I/O
操作的完成或數據的返回,而只是將I/O
請求發送到操作系統,繼續執行下一條語句。當操作系統完成I /O
操作時,以事件的形式通知執行I/O操作的線程,線程會在特定時候處理這個事件。為了處理異步I/O
,線程必須有事件循環,不斷地檢查有沒有未處理的事件,依次處理。 --《Nodejs開發指南》
如果JavaScript
是阻塞I/O
,拿之前加載更多評論的例子看來,只要數據還沒有從服務器返回,所有后續的操作都將阻塞,比如點擊其他綁定了事件處理程序的按鈕。幸運的事,正如《Nodejs開發指南》提到的一樣,線程必須有事件循環,也就是剛剛說到的Event Loop
!那么非阻塞I/O
也就自然而然地理解了。至於事件驅動,它和非阻塞I/O
應當是因果關系的,因為JavaScript
是基於事件驅動的,所以成就了非阻塞I/O
的特性。因為要做到異步的話,常用的就是發送異步請求,請求相應之后,執行回調事件,事件在JavaScript
中無處不在。
Node安裝
與Python等安裝不同的是,Nodejs在Windows下面的安裝反而比在Linux下面簡單的多。本來想自己寫安裝過程的,發現W3CSchool講解的非常准確,所以這里只給出鏈接。安裝教程鏈接:http://www.w3cschool.cc/nodejs/nodejs-install-setup.html
你可以通過node -v
命令來檢測是否安裝成功:
后話
本教程旨在給出一個實戰教程,這一章主要是介紹Nodejs和JavaScript的運行原理,上一章講解了MongoDB的入門教程,如果你想跟隨本教程學習,可以從上一篇文章看起《Node+Express+MongoDB+Socket.io搭建實時聊天應用實戰教程(一)--MongoDB入門》,與大家探討技術。本系列教程同步到個人的Github:https://github.com/yuanzm/MongoDB-demo.如需轉載,請務必注明原文鏈接
參考資料
http://www.infoq.com/cn/articles/tyq-nodejs-event
http://www.jb51.net/article/53812.htm
http://www.ituring.com.cn/article/5779
http://www.w3cschool.cc/nodejs/nodejs-install-setup.html
http://www.ibm.com/developerworks/cn/web/1201_wangqf_nodejs/