koa2:Node.js開發一個同步伺服器

大多數教程一上來直接就告訴我,node.js是如何的高並發,如何的牛逼,然後告訴我這是一個事件驅動的運行機制,所以才能夠很輕易的實現:單線程+高並發。然後duang duang duang的擼幾行代碼出來,讓大家看。

但是對於新手而言,我們甚至連開發一個同步伺服器的能力都不健全,我們怎麼能比較同步和非同步的區別呢?然後加上,我們又只會使用js的情況下(注意,不是我,我還會c++,java,oc,python.....),選擇其他的語言來實現同步伺服器和node.js對比,著實是一個比較不效率的辦法。那我們能不能直接用node.js實現一個同步伺服器和非同步伺服器,這樣子我們就能夠很清楚的看出,在同一個環境下,同步伺服器和非同步伺服器有什麼不同。

同步伺服器

// 導入http模塊:var http = require("http");var fs = require("fs");var server = http.createServer(function (request, response) { let maopianBuffer = fs.readFileSync("./我是一個1G的飯島氏動作片.avi"); response.end(maopianBuffer);});// 讓伺服器監聽8080埠:server.listen(8080);console.log("Server is running at http://127.0.0.1:8080/");

幾行代碼,我們就先實現了一個非常簡單的同步伺服器,這個伺服器並不具備任何的並發能力。

  • fs.readFileSync:當我們調用這個介面的意思就是去讀取本地磁碟的「./我是一個1G的飯島氏動作片.avi」這個文件。由於這個文件大小是1G,因此讀取時間可能會在1-10秒不等,那麼也就是說,在這1-10秒的時間裡,其他任何人訪問你的網站,都無法觀看影片。

這就是同步伺服器蛋疼的一個地方,為了解決這個問題,其他語言會採用多線程/多進程的方式去解決。但是我們採用的是node.js這樣一個單線程的引擎,所以也就意味著我們使用同步伺服器就會:

A和B同時訪問127.0.0.1:8080/,假設fs.readFileSync要讀10秒,那麼最終A和B兩人都看到網站內容的總時間是:20秒

沒錯,這就是一個簡單的排隊機制,就好像你去飯堂,如果飯堂只開放一個阿姨給你打菜,那麼你就必須等前面那個人打完飯你才能開始打飯。實際上,人們也沒那麼豬頭三,一般飯堂會開設4-5個阿姨給你搞,這就是我們說的「並發」!

並發伺服器

// 導入http模塊:var http = require("http");var fs = require("fs");var server = http.createServer(function (request, response) { fs.readFile("./我是一個1G的飯島氏動作片.avi",(err,data)=>{ if(err){ console.log("出錯") } else{ console.log("maopian讀取完畢") response.end(data); } }); console.log("函數運行結束")});// 讓伺服器監聽8080埠:server.listen(8080);console.log("Server is running at http://127.0.0.1:8080/");

  • fs.readFile:我們很明智的選擇了一個非同步函數,這個函數的特點就是程序運行這個函數的時候,不會卡住,而是直接往下走,當這個函數讀取完畢以後,就會進入回掉函數( err,data)=>{}里的內容
  • response.end():這個函數極其重要,這個函數的調用代表著「你,伺服器開發者,想要什麼時候結束本次會話」,如果你不調用這個函數,你的伺服器就會無限的進入等待。只有當你調用這個函數以後,你才能真確的返回給用戶一些信息。

運行,當你訪問127.0.0.1:8080/的時候,你會看到如下的輸出:

函數運行結束maopian讀取完畢

我們可以看到,「函數運行結束」這行字最先輸出,然後到「maopian讀取完畢」,可以看到的是,我剛剛說的「fs.readFile」並沒有阻塞,而是直接走到了函數的末尾。等到這個函數執行完畢以後,我們的「maopian讀取完畢」得以運行,然後再調用response.end()這個函數,我們的瀏覽器請求終於得到了回復,我們也看到了我們想要的maopian。

那麼這個伺服器和同步伺服器的區別是什麼呢?答案就是「不再排隊了」。「fs.readFile」函數相當於會製造無數個阿姨,管你有幾個人,我阿姨就是夠多,你來無數個人也好,我總共耗時就是:「10秒」。

A、B、C、D同時訪問127.0.0.1:8080/,假設fs.readFile要讀10秒,那麼這4個人都看到網站內容的總時間就只是:10秒

至於這個fs.readFile是如何製造無數個阿姨的?這個問題,實際上會牽涉到Node.js底層的運轉!不過不要害怕,其實也很簡單,不過本章還是不多做描述了,我們先學會用,然後再學習原理!

總結

  • 實際上node.js並不「直接幫你」並發,而是通過某些函數調用使得我們獲得並發能力,如果處理不妥當,你使用了某個「同步的」函數,那麼你的Node.js伺服器就會卡住等待這個同步的函數執行完畢才往下走。這一點對於之後理解Koa的非同步編程極其重要。
  • response.end(data)是一個比較重要的函數,這個函數直接決定了,你什麼時候,返回什麼內容給用戶 ,如果調用不甚,或者是調用錯誤,可能造成的結果就是用戶根本得不到其想要的東西!

推薦閱讀:

網站的消息(通知)系統一般是如何實現的?
Ajax 更靈活和友好,那表單現在還有什麼優勢和意義呢?
面對JDK的BUG該如何是好?
《黑客帝國》中,NEO尼奧為什麼不教其他人超能力,只教會了他們膽大妄為?
QQ for PC的防撤回

TAG:Nodejs | JavaScript | 编程 |