認識 Node .js

前言

本文將介紹Node.js的一些基本概念,包含它的歷史,特性和簡單的使用等。若是你有過服務端的編程經驗,那麼你將能很快熟悉它。javascript

Node.js是什麼

圖片描述

這是Node.js官網上對其的定義,就是說,Node.js是一個javascript運行平臺,該平臺基於chrome v8 引擎。V8讓Node.js在性能上獲得了巨大的提高,由於它去掉了中間環節,執行的不是字節碼,用的也不是解釋器,而是直接編譯成了本地機器碼。(注意:v8 5.9 發佈後,Ignition 字節碼解釋器將默認啓動,v8 又回到了字節碼的懷抱,具體請參閱:https://cnodejs.org/topic/590...html

Node.js帶來的好處

對一名前端而言,Node無疑有以下幾個好處:前端

  1. 開發人員用一種語言就能編寫整個Web應用,這能夠減小開發客戶端和服務端時所需的語言切換。
  2. 有些NoSQL數據庫中用的就是JavaScript語言,(好比CouchDB和MongoDB),因此跟它們配合使用很是方便。
  3. Node用的虛擬機(V8)會緊跟ECMAScript標準。換句話說,在Node中若是想用新的JavaScript語言特性,不用等到全部瀏覽器都支持。

特色

Node.js採用的是事件驅動、非阻塞I/O的設計模型。你們想到了什麼?這和javascript在瀏覽器上的運行機制是同樣的。
另外,對於高併發的處理,傳統平臺採用的是多線程方案,而Node.js則採用的是單線程、事件驅動、非阻塞I/O的設計模型。java

咱們來看一個瀏覽器中的例子node

$.post('/resource.json', function (data) {
  console.log(data)
})
// 繼續執行

上面代碼是瀏覽器中的一個ajax請求,假如該請求須要耗費600ms,該ajax請求會在事件輪詢的外面執行(腳本執行的主順序以外),而後當這個ajax請求完成時(600ms後),它會發出一個「事件」,會有一個函數(一般稱做「回調」)來處理它。
這個操做是異步的,並不會「阻塞」腳本執行,事件輪詢仍然能夠響應頁面上執行的其餘交互或請求。這樣,瀏覽器能夠對客戶作出響應,而且能夠處理頁面上的不少交互動做。 ajax

咱們再來看一個服務器中的例子:chrome

// 數據庫查詢操做
db.query('SELECT * FORM work', function (data) {
    console.log(data)
  }
)

這段代碼作了些I/O操做,而且在全部數據回來以前,這個進程並不會被阻塞。在Node中,I/O幾乎老是在主事件輪詢以外進行,使得服務器能夠一直處於高效而且隨時可以作出響應的狀態,就像NGINX(帶有異步I/O的事件輪詢的一種http服務器)同樣。這樣進程不會受I/O限制,由於I/O延遲不會拖垮服務器。所以一些在服務器上曾經是重量級的操做,在Node服務器上仍然能夠是輕量級的。數據庫

dirt程序

Node所針對的應用程序有一個專門的簡稱:DIRT。它表示數據密集型實時(data-intensive real-time)程序。上面已經提到,Node自身在I/O上很是輕量,能在處理大量請求時保持不少開放的鏈接,而且只佔用一小部份內存,因此,它特別擅長處理數據密集型實時應用。好比在線文檔協做、對臨近公交車的實時精肯定位,以及多人在線遊戲等。編程

簡單的例子

接下來咱們先看一些簡單的例子。json

文件操做

var fs = require('fs')

fs.readFile('./package.json', 'utf8', function (er, data) {
  console.log(data)
})

這段程序是要從硬盤裏讀取package.json文件。當全部數據都讀出來後,就會調用那個回調函數。require('fs')是指加載Node提供的文件模塊,讀取的文件內容將用utf8進行編碼。

HTTP服務器

若是你有 PHP 開發經驗,會知道在成功運行 PHP 以前先要配置一個功能強大而複雜的 HTTP 服務器,譬如Apache、IIS 或 Nginx,還須要將 PHP 配置爲 HTTP 服務器的模塊,或者使用 FastCGI 協議調用 PHP 解釋器。這種架構是「瀏覽器 - HTTP 服務器 - PHP 解釋器」的組織方式,而Node.js 將「HTTP服務器」這一層抽離,直接面向瀏覽器用戶。以下圖所示:
圖片描述

接下來,讓咱們建立一個 HTTP 服務器吧。創建一個名爲 app.js 的文件,代碼以下:

var http = require('http')

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'})
  res.write('<h1>Node.js</h1>')
  res.end('<p>Hello World</p>')
}).listen(3000)

console.log("HTTP server is listening at port 3000.")

上面代碼中,建立HTTP服務器調用了http.createServer()函數。它只有一個參數,是個回調函數,服務器每次收到HTTP請求後都會調用這個回調函數。這個請求回調有兩個參數,請求和響應對象,一般簡寫爲req和res。服務器每收到一條HTTP請求,都會用新的req和res對象觸發請求回調函數
res.writeHead()方法設定了響應狀態碼爲200和響應頭中的Content-Type爲text/html類型。
response.write()方法表示向請求的客戶端發送響應內容。 內容能夠是一個Buffer或字符串,表示要發送的內容。
Node不會自動往客戶端寫任何響應。在調用完請求回調函數以後,就要由你負責用res.end()方法結束響應。因此,最終程序用res.end('<p>Hello World</p>')結束了一次響應。

在終端中運行node app.js 命令,打開瀏覽器訪問 http://127.0.0.1:3000 試試吧。

Node在處理數據流上也很強大。你能夠把數據流當作特殊的數組,只不過數組中的數據分散在空間上,而數據流中的數據是分散在時間上的。經過將數據一塊一塊地傳送,開發人員能夠每收到一塊數據就開始處理,而不用等全部數據都到全了再作處理。
下面咱們看一個例子:

var fs = require('fs')
var stream = fs.createReadStream('./package.json')

stream.on('data', function (chunk) {
  console.log(chunk)
})
stream.on('end', function () {
  console.log('finished')
})

只要有新的數據塊準備好,就會激發data事件,當全部數據塊都加載完以後,會激發一個end事件。
程序能夠邊讀取邊處理,這要比等着全部數據都緩存到內存中再處理效率高得多
Node中也有可寫數據流,能夠往裏寫數據塊。當HTTP服務器上有請求過來時,對其進行響應的res對象就是可寫數據流的一種。
可讀和可寫數據流能夠鏈接起來造成管道,這是一種高效的數據處理方式,只要有數據準備好就能夠處理,不用等着讀取完整個資源再把它寫出去。
用咱們上面的HTTP服務器,看看如何把一張圖片流到客戶端:

var http = require('http')
var fs = require('fs')

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'image/png'})
  fs.createReadStream('./img.png').pipe(res)
}).listen(3000)

console.log('Server running at http://localhost:3000/')

在這行代碼中,數據從文件中讀進來(fs.createReadStream),而後數據隨着進來就被送到(.pipe)客戶端(res)。在數據流動時,事件輪詢還能處理其餘事件。

小結

相信讀到這裏,你們對Node的優點和特性已經有了一些瞭解,而且經過本文的三個編程小例子,對Node的一些用法也有了一些體會,Node跟全部技術同樣,並非萬能藥。它擅長解決某些問題,併爲咱們帶來方便。一樣的,在某些方面,倒是它的短板,好比:計算密集型應用。但願你能在用Node開發以前,多一些合理的考慮,多一份編程的快樂。

相關文章
相關標籤/搜索