為什么要讀Nodejs源碼?
本文轉(zhuǎn)載自微信公眾號(hào)「編程雜技」,作者theanarkh。轉(zhuǎn)載本文請(qǐng)聯(lián)系編程雜技公眾號(hào)。
前幾天有個(gè)同學(xué)和我說(shuō),他在看nodejs源碼,但是不知道為什么需要看,也不知道從中可以學(xué)到什么。所以今天想聊一下關(guān)于閱讀nodejs源碼的意義。閱讀其他源碼也類似。
首先,閱讀源碼的目的無(wú)非兩個(gè)
- 1 深入了解和理解他或一些底層的原理
- 2 從中學(xué)到一些優(yōu)秀的設(shè)計(jì)思想和實(shí)踐。
如果你沒(méi)有兩個(gè)目的,那其實(shí)就沒(méi)有必要去看源碼了。那接下來(lái)聊一下從閱讀nodejs源碼中,可以得到什么。
首先我們要深刻理解到nodejs是什么?大家都知道nodejs是一個(gè)js的運(yùn)行時(shí)。那么到底nodejs里面有什么呢?每一部分的意義是什么呢?首先nodejs的組成是libuv、v8、第三方庫(kù)。nodejs的定位首先是一個(gè)服務(wù)器,所以其實(shí)有l(wèi)ibuv就可以了。那么剩余的組成部分有什么用?第三方庫(kù)的作用很明顯,就是復(fù)用了業(yè)界已有的解決方案去拓展了nodejs的一些功能,并不是nodejs的核心。v8的意義是因?yàn)閚odejs選用了js這個(gè)語(yǔ)言,所以就需要一個(gè)js的引擎。否則v8也是不需要的,直接把libuv和第三方庫(kù)編譯成二進(jìn)制就行,類似nginx,redis一樣。這個(gè)是高層的視圖。從底層來(lái)看,libuv是對(duì)操作系統(tǒng)功能的封裝,v8是一個(gè)js解釋器。那么看nodejs源碼的意義就很明顯了。nodejs的源碼從垂直分為以下三個(gè)部分
- 1 js層
- 2 c++層(使用v8橋接js和libuv和一些自定義的c++邏輯)
- 3 c層
讀js層,你可以了解到nodejs實(shí)現(xiàn)的一些上層的邏輯,雖然js層最后還是依賴底層,但是js層也有很多邏輯,看懂了js層,在使用nodejs的時(shí)候,也就能更加深刻地了解到你在做什么,nodejs在做什么。但是js層是遠(yuǎn)遠(yuǎn)不夠的。因?yàn)樗皇莻€(gè)殼子。
那么接下來(lái),你就要去讀c++層,讀c++層的代碼,更多的是在了解如何去使用v8。假設(shè)你以后想在你的其他項(xiàng)目中單獨(dú)使用v8,那么nodejs的代碼就是一個(gè)參考。那么我們了解v8的使用有什么意義呢?這個(gè)問(wèn)題相當(dāng)于我們使用一個(gè)語(yǔ)言,然后了解他的編譯器/解釋器有什么意義。很多時(shí)候,我們都不需要這樣做,這完全取決于你的興趣。如果你以后想使用v8,或者你想了解js實(shí)現(xiàn)的底層原理,又或者你想了解一個(gè)編譯器/解釋器是如何實(shí)現(xiàn)的。那么你就可以去學(xué)習(xí)v8。v8首先作為一個(gè)js引擎,他里面有一個(gè)編譯器/解釋器的通用邏輯,詞法解析,語(yǔ)法解析,代碼生成,代碼優(yōu)化等等。然后還包含了js語(yǔ)言本身的實(shí)現(xiàn)細(xì)節(jié),比如一個(gè)js數(shù)組,一個(gè)js對(duì)象,在v8里是怎么實(shí)現(xiàn)的。最后,了解v8為我們暴露了什么接口,我們可以使用v8做什么。
最后就是讀libuv,nodejs的重點(diǎn)是作為服務(wù)器,所以相對(duì)來(lái)說(shuō),讀libuv的才是重點(diǎn),我們都知道v8只是一個(gè)js引擎,他沒(méi)有網(wǎng)絡(luò),dns、文件等能力。在前端,js的文件,網(wǎng)絡(luò)等能力來(lái)源于宿主瀏覽器。在nodejs,這些能力就來(lái)源于libuv。這是nodejs為什么叫nodejs,而不叫v8。因?yàn)樗恢皇莢8。他還實(shí)現(xiàn)了自己的一些功能。所以你也可以實(shí)現(xiàn)自己的功能,加上v8的能力,創(chuàng)造出一個(gè)新的服務(wù)器。言歸正傳,那么讀libuv可以學(xué)到什么東西呢?libuv是實(shí)現(xiàn)服務(wù)器的核心。所以我們可以從libuv中學(xué)習(xí)到實(shí)現(xiàn)一個(gè)服務(wù)器用到的技術(shù)。從libuv官網(wǎng)中我們也可以知道,libuv包括了進(jìn)程、線程、定時(shí)器、文件、tcp、udp、unix域、線程池、dns等等能力,使用到操作系統(tǒng)能力包括進(jìn)程間通信(管道、unix域、eventfd)、線程池、事件驅(qū)動(dòng)(epoll、select、poll、kqueue等)、inotify機(jī)制、文件操作等等,使用數(shù)據(jù)結(jié)構(gòu)和算法有二叉堆、紅黑樹(shù)、隊(duì)列等。
總的來(lái)說(shuō),閱讀nodejs源碼最直接的是理解nodejs的工作原理和nodejs的本質(zhì)。如果你是一個(gè)nodejs的開(kāi)發(fā)者,這無(wú)疑是一個(gè)很好的收獲。其次,如果你有興趣,你還可以了解到編譯器,操作系統(tǒng)的知識(shí)。額外地,你也可以學(xué)習(xí)到nodejs中的一些設(shè)計(jì)思想,比如定時(shí)器的設(shè)計(jì),從早期版本到后來(lái)的重構(gòu)背景。又或者如果你來(lái)設(shè)計(jì)一個(gè)服務(wù)器,你怎么設(shè)計(jì)。
從理論上聊了一下閱讀nodejs源碼的一些看法,下面順便聊一下我自己的看法和體會(huì)。我閱讀nodejs源碼的原因是非常直接的,因?yàn)槲蚁M页蔀橐粋€(gè)優(yōu)秀的nodejs工程師。我對(duì)v8和libuv本身并沒(méi)有太大興趣。雖然我一直是一個(gè)前端工程師,但是我也不會(huì)去讀js引擎的源碼。至于libuv,相關(guān)的異步io庫(kù)非常多,而且說(shuō)到服務(wù)器的設(shè)計(jì),nginx、redis無(wú)疑是更值得讀的。但是成為一個(gè)優(yōu)秀的nodejs工程師,深入了解和深刻理解nodejs本身是非常必要的。相對(duì)來(lái)說(shuō),nodejs是非常原生的。很多時(shí)候我們覺(jué)得讀nodejs源碼沒(méi)有意義是因?yàn)闆](méi)有深度或廣度地去使用nodejs,可能只是停留到框架層面,復(fù)制著業(yè)務(wù)的最佳實(shí)踐,成功地避開(kāi)了一些坑。當(dāng)你遇到一些難題,卻又難以解決,甚至業(yè)界也沒(méi)有解決方案的時(shí)候,你就會(huì)深刻理解到閱讀源碼的意義。當(dāng)然,這種時(shí)候可能不會(huì)很多(比如https://cnodejs.org/topic/600b9de15d04ac76cf2181a7和https://cnodejs.org/topic/6018f1b103d797fb8e66e71c#6019f31903d7976d1066e9d2等)。
從開(kāi)始讀nodejs源碼到現(xiàn)在,我覺(jué)得這是一段非常艱難、快樂(lè)、深刻的經(jīng)歷。他讓我不僅更了解和理解nodejs,也在更高層面地提高了我。雖然我一直在推廣閱讀nodejs源碼、寫(xiě)了很多文章、也和其他同學(xué)進(jìn)行了很多交流。但是并不說(shuō)明非讀源碼不可,個(gè)人覺(jué)得,讀源碼是一種好的習(xí)慣,也是讓你變得優(yōu)秀的方式,但是因?yàn)樽x哪些源碼,這個(gè)完全取決于個(gè)人的興趣和選擇。不要盲目地去讀,要帶有目的。對(duì)個(gè)人而言,我是非常感謝nodejs,也非常敬佩nodejs作者和貢獻(xiàn)者,但是我覺(jué)得我在閱讀nodejs源碼中,更多的是了解了nodejs的原理,并沒(méi)有學(xué)到太多我想學(xué)的東西,v8算一方面,而libuv的內(nèi)容,我覺(jué)得看nginx和操作系統(tǒng)內(nèi)核可能是更好的選擇,但是libuv相比來(lái)說(shuō)可能更輕量,更快了解一個(gè)異步框架的設(shè)計(jì)。
這里順便提一下nodejs源碼分享的事情,有些同學(xué)希望我講得通俗一點(diǎn),或者結(jié)合應(yīng)用來(lái)講。這里說(shuō)一下我做分享的一些想法。首先,我是一個(gè)在nodejs源碼中學(xué)習(xí)的人,而不是站在nodejs之上的人,這意味著我也在慢慢學(xué)習(xí),并且因?yàn)闀r(shí)間關(guān)系,我沒(méi)有辦法像圖解系列,碼農(nóng)翻身一樣講得那么好那么易懂。因?yàn)槲业某踔云鋵?shí)是做個(gè)筆記,然后分享給有興趣的人,然后大家一起來(lái)做這個(gè)事情。我不是大家的老師,這也不是我的初衷和目的。我?guī)缀醵际敲赓M(fèi)分享內(nèi)容、免費(fèi)答疑。但是卻很少碰到真正的志同道合者,大家還希望我講得通俗易懂這對(duì)我來(lái)說(shuō)就未免太難了。我承認(rèn)如何講好技術(shù),做一個(gè)好的分享是一個(gè)值得學(xué)習(xí)的事情,但是我覺(jué)得這不是我現(xiàn)階段的目的。而且我覺(jué)得一個(gè)有上進(jìn)心的程序員,自己多動(dòng)一下手和大腦,這個(gè)要求并不過(guò)分。一人之力有限,希望大家明白。
最后,提前祝大家新年快樂(lè)!對(duì)nodejs感興趣的同學(xué)也可以找我一起交流學(xué)習(xí)!