前言
之前做過Nodejs的架構篇, 有很多朋友留言給我,說沒看懂里面的例子,這里我會重新梳理一下,再以http server為例,來解析Nodejs從前端到libuv的調用過程。
正文
回憶a. Nodejs提供了許多功能接口(又稱標准庫),例如:http,net,socket etc
回憶b. 這些庫是由C/C++寫成,並且對外提供服務
回憶c. libuv負責異步調用工作(event loop)
這是上一篇我們使用過得流程圖,從V8角度出發,描述了建立http server,js 到C/C++的過程,同時也包括了調用后端的參與者(tcpwrap,libuv)。圖中1,2,3,4,5這些步驟是一個同步調用的過程,始於server.listen(),終於第5步,也就是server.listen()之后。
server.listen()發起的請求不一定會被處理完,V8會繼續執行js代碼。
當server.listen()發起的請求被處理完之后,libuv發起一個逆向的callback,始於libuv中的event loop,終於server中設置的callback函數,而這期間,V8可能已經完成了多條任務(小心回調地獄),這就是異步的優勢所在。
PS:高並發不等同於高效率,我們以Nodejs的食堂為例,窗口阿姨調度得當,他很快地將飯菜分給學生,這不代表學生能夠馬上吃到飯,因為學生要慢慢地找到空閑的位置才能開始吃飯。(這里稍微吐槽下,Nodejs的運算速度比PHP5還要慢,不適合做邏輯復雜的項目)
一個簡單的http server 例子:
var http=require("http"); http.createServer(function(req,res){ res.writeHead(200,{ "content-type":"text/plain" }); res.write("hello nodejs"); res.end(); }).listen(3000);
幾行代碼便可跑起一個http server,看似簡單,背后肯定發生了很多故事。
我們來看下圖,從createServer開始分析。
從上至下可分為兩部分:
第一部分=創建一個server實例,這部分還是集中在js部分,其中http.js,http_server.js以及net.js為Nodejs庫中的代碼,這部分比較重要的細節是net.js,集成了若干API,這些API會為之后提供服務。
第二部分=從調用this.listen()開始,可以清楚地看到,第二部分直接調用net.js提供的api。createTCP()通過 process.binding('tcp_wrap').TCP 進入到Nodejs C/C++部分,也就是圖2 TCPWrap部分。在回來net.js的倒數第二步,handle.open(fd),這部分代碼最終調用到C/C++部分的TCPWrap::Open()。
看完了這篇文章,是不是更清晰地了解Nodejs的運行原理了!