Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境
Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效
Node.js 的包管理器 npm,是全球最大的開源庫生態系統
? 本文主要介紹構建一個 Node.js 應用的基本步驟和模塊,並假定你已經對 Node.js Api 有必定的瞭解javascript
? 本文引用部分代碼做爲例子,若是但願參看所有源碼,歡迎去 github 查閱(若是以爲有必定幫助,歡迎star)html
整個 Node.js 應用的架構設計java
require
指令來引入 Node.js 模塊// 經過 require 引入 http 模塊,並將實例化的 HTTP 賦值給 http 變量 const http = require('http'); // 引入 url 模塊,用來解析數據 const url = require('url'); function ylone(router, handleObj) { const hostname = '127.0.0.1'; const port = 7777; // http.createServer(function(){}) 方法建立服務器,並返回一個對象 const server = http.createServer((req, res) => { const path = url.parse(req.url); const pathName = path.pathname; // 處理node.js每次自動請求favicon.ico if (pathName !== '/favicon.ico') { const content = router(handleObj, pathName, res, req); } }); // server.listen() 方法綁定主機和端口 server.listen(port, hostname, () => { console.log(`服務運行在${hostname}:${port}`); }); } exports.ylone = ylone;
http.createServer((req, res) => {...})
是一個典型的回調,事實上,這就是 Node.js 原生的工做方式index.js
去調用相應的模塊來引導和啓動應用const server = require('./http'); const router = require('./route'); const handle = require('./requestHandle'); var handleObj = {}; // 入口 Case handleObj['/'] = handle.hello; // 非阻塞 Case handleObj['/vlone'] = handle.vlone; // post Case handleObj['/supreme'] = handle.supreme; // get Case handleObj['/adidas'] = handle.adidas; server.ylone(router.router, handleObj);
http.createServer((req, res) => {...})
的 req 參數中,爲了解析 req,須要額外引入 url
和 querystring
Node.js 模塊http.createServer((req, res) => {...})
內解析 req 參數,而後調用 router 方法function router(handleObj, pathName, res, req) { if (typeof handleObj[pathName] === 'function') { return handleObj[pathName](res, req); } else { res.writeHead(200, { 'Content-type': 'text/plain' }); const content = '404 Not Found'; res.write(content); res.end(); } } exports.router = router;
由於文章篇幅緣由,這裏只展現關鍵代碼,源碼參看 githubnode
const { exec } = require('child_process'); const querystring = require('querystring'); const url = require('url'); function createHttp(type, res, val) { const content = val; const conType = { plain: 'text/plain;charset=utf-8', html: 'text/html', }; // 爲隱式的響應頭設置值 res.writeHead(200, { 'Content-type': conType[type] }); // 發送響應主體 res.write(content); // http 完成響應 res.end(); } ... something else function vlone(res) { exec('node --version', (error, stdout, stderr) => { if (error) { console.log(error, stdout, stderr); return; } const content = stdout; const type = 'plain'; createHttp(type, res, content); }); } ... something else
A() 方法讀取文件,所以須要必定的響應時間,B() 方法表明其餘須要執行的代碼git
阻塞:在A() 執行的過程當中,B() 處於等待狀態,當A() 訪問文件數據準備就緒後,B() 纔開始執行github
由上圖能夠看出,應用程序從進行系統調用到複製數據報到應用進程緩衝區的整段過程是阻塞的,直到數據報被複制到用戶空間完成後,用戶進程才解除阻塞狀態,繼續執行下一個應用程序npm
非阻塞:在A() 執行的過程當中,B() 同時執行,且當A() 訪問文件數據準備就緒後,A() 會被執行完成編程
由上圖能夠看出,應用程序在調用過程當中,若是數據報尚未準備就緒,會先返回一個錯誤信息(EWOULDBLOCK),此時當前進程能夠執行其餘方法,而不會阻塞。而 A() 會輪詢內核,返回緩衝區數據是否準備就緒api
url.parse()
的第二參數 parseQueryString 若是爲 true,則 query
屬性老是會經過 querystring 模塊的 parse() 方法生成一個對象node ylone.js
命令執行腳本http://localhost:7777/
)意味着向服務器發出請求,從而觸發服務器建立時的回調函數http://localhost:7777/
)時,控制檯可能會輸出兩次 req 的數據,那是由於大部分瀏覽器會在訪問網頁時嘗試讀取 favicon.ico 文件/favicon.ico
的問題,能夠在 http 中對其進行過濾,不執行操做res.writeHead(200, {'Content-type': 'text/plain'})
的 Content-type 設置爲 text/html
res.writeHead(200, {'Content-type': 'text/plain;charset=utf-8'})
加上 charset=utf-8
配置解決--Respect Node.js--瀏覽器