官术网_书友最值得收藏!

前言

寫這本書是我在2016年底許下的愿望,希望在2018年初完成一本技術專著。

我于2012年加入Node.js開發的大軍,現在也有幸成為Node.js這個項目的Core Collaborator之一。所以,我的意向就是為大家呈現一本Node.js領域相關的書。但是現在市面上相關的書籍其實有很多了,我再寫一本日常開發類的圖書就顯得有些多余。反而是在Node.js的C++擴展開發方面,無論是在國內還是在國外,都是一塊死角。就目前而言,國外市場我也只看到過一本電子書,并沒有紙質圖書出版,國內就更沒有了。

Node.js作為近幾年新興的一種編程運行時,托Chrome V8引擎的福,在作為后端服務時有比較高的運行效率,在很多場景下對于我們的日常開發已經足夠用了。不過,它也跟“PHP提供了C語言開發其原生擴展的方式”類似,為開發者開了一個使用C++開發Node.js原生擴展的口子,讓開發者進行項目開發時有了更多的選擇。

實際上,在Node.js的生態圈中,就有很多使用C++完成的包。如最近比較火的深度學習TensorFlow,其Node.js版本的封裝就是基于官方的C++源碼完成的。我自己就是在日常開發中有一些相應的需求,使用純粹的Node.js來開發可能會使開發成本有點大,或者基本上做不到,又或者有性能上的要求。這時,我就會選擇使用C++來實現它的一個擴展。在我寫了一段時間C++擴展之后,想到可能在社區中有很多像我一樣的人,苦于Node.js在底層操作時的一些局限性,如果他們也加入C++原生擴展開發陣營的話,興許要再踩一遍我以前踩過的“坑”,找我之前找過的資料。因此,我就想把自己一路走來的經驗分享給大家,讓更多的人順利地加入Node.js的C++原生擴展開發的大軍中。

我的Node.js之路

我個人從小學開始接觸靜態網頁的開發,直到高中開始參加信息學奧林匹克競賽(Olympiad in Informatics,OI),才算正式踏入了編程之路。

在大學的時候我仍舊堅持參加大學生程序設計競賽(ACM International Collegiate Programming Contest,ICPC),并且一直使用C++和PHP進行開發。也是那時我打下了C++基礎,這樣才有機會現在完成這本書的寫作工作。

我接觸Node.js其實并沒有國內一些早期的布道者們早,相反還是有點遲的。在2012年底,我決心學習Node.js,從而完成自己的一個創業項目。我當時的學習方法特別簡單,買了一本BYVoid的《Node.js開發指南》,就算正式踏入了Node.js領域。

在熟悉了Node.js之后,我開始為Node.js生態圈造輪子,如Toshihiko一個極簡、自帶黑盒緩存層的ORM,詳見https://github.com/XadillaX/Toshihiko。、ThmclrX一個圖片主題色提取的包,詳見https://github.com/XadillaX/thmclrx。、Huaming隨機起名神器,詳見https://github.com/boogeedoo/hua。、mcnbtMinecraft游戲的*.nbt文件解析庫,詳見https://github.com/BoogeeDoo/mcnbt。等。其實我個人認為,造輪子與寫業務的一個不同點在于,造輪子可能會更容易遇到語言或是Node.js運行時本身的“坑”。所以,這就促使我去深究Node.js的文檔,甚至源碼。托我之前習得的C++基礎的福,在閱讀Node.js源碼時并不覺得特別艱難。

我在老東家花瓣網的時候,就已經初步開始了Node.js的C++擴展開發。

后來我去了上一家就職的公司——大搜車,負責公司Node.js團隊的建設。當時我就開始更深入地挖掘Node.js的一些內容了。甚至在2017年年中的時候,我通過給Node.js貢獻源碼,成為Node.js Core Collaborator之一。我在為Node.js貢獻源碼的時候,也為本書第3章和第6章的寫作打下了基礎。

原生擴展的一些示例

在Node.js早期的版本中,運行子進程是純異步的,并沒有像現在一樣的各種spawnSync()等函數。我當時寫了一個命令行工具,在其所用到的一個幫助類中實現一個參數校驗的函數必須同步返回一個布爾類型的值;然而我在這個校驗函數中所需要做的事情就是判斷當前系統的Git版本。也就是說,我要通過子進程啟動$ git-v,并得到它的結果看看版本是不是符合要求。當時Node.js中運行子進程是異步的,達不到我的要求,所以我自己使用C++封裝了一個原生擴展,使其能在Node.js的事件循環中同步開啟子進程并在其結束后獲得它的終端輸出——雖然Node.js天生異步,但是在我的一個命令行工具中用同步形式執行這些內容也是沒有問題的。

再比如,在大搜車的時候,項目用了阿里云的消息隊列服務,而這款產品當時只有閉源的Java、C++等SDK,而C++的SDK就只提供了幾個動態鏈接庫和一堆頭文件,我們使用Node.js的開發者就完全沒法使用其服務。如果一定要用Node.js進行開發,一個成本比較高的做法就是自己去逆向分析及研究消息隊列服務的各種網絡包的結構,自己解析,然后用Node.js實現一個同樣功能的庫。然而這個方法基本不可行——尤其是在我們的項目高速迭代的時候。那么另一個辦法就是基于其閉源的C++SDK,使用本書中的各種開發方式,寫一份Node.js的C++擴展。這樣就能把它們的C++SDK集成到我們的Node.js項目中了。這是一個非常好的降低開發成本的方法。

當年我還在花瓣網的時候,有一個需求是提取一張圖片的主題色。我當時翻閱了不少論文,最終采用了一種八叉樹加最小差值法的結合體八叉樹提取法加最小差值法的混合算法,詳見我的博客《圖片主題色提取算法小結》一文:https://xcoder.in/2014/09/17/theme-color-extract/。來完成這個需求。在數據結構和整型數字處理方面,我個人認為C++的開發效率和執行效率比Node.js要高,于是我自然而然地就使用了C++把核心算法部分完成了(現在我甚至使用C語言又重構了一套,開源在GitHub上面C語言的主題色提取庫,“圣·白蓮”,詳見https://github.com/XadillaX/byakuren。)。然后為了將其集成到我們的Node.js任務調度系統中,我又將其封裝成了一個Node.js的C++的擴展。這樣一來,主題色提取的任務就歡快地運行了——它也被開源在我的GitHub上面,就是前面提到過的ThmclrX。而且借這個包的“東風”,我的碩士畢業論文寫的就是這么一套主題色提取的任務系統相關內容。

類似的案例還有很多。如計算字符串哈希值等,由于用JavaScript重寫代碼的時候,在整數的各種操作上會有很多“坑”,因此拿C++源碼封裝一下就非常簡單了。甚至谷歌推出的CityHash這個算法只有一份冗長的C++源碼,使用JavaScript重寫的話將會是一個比較龐大的工作量;再比如解析MP4文件的時長,我個人不是多媒體相關領域的開發者,所以并不擅長。于是我弄了一份C++的源碼,懶得轉換——嘿,用C++擴展一包,直接就發布了;還有同步獲取HTTP API的內容,寫一個能繼承的類似于ECMAScript 6中Proxy特性的攔截器;等等。

本書面向的讀者

在閱讀本書前,我希望你對Node.js比較熟悉,并且對于C++這門語言至少要有一個初步的認識。當然,如果你的C++基礎并不是很好的話,也不要怕,可以多讀幾遍本節最后的一段話。

本書不僅僅講實踐,我還花了不少篇幅來講解它的前驅知識,如Chrome V8引擎開發的一些基本概念,如句柄、句柄作用域等,以及各種API的初步介紹。另外,書中還介紹了libuv層面的內容,尤其是在異步方面,像libuv中的線程、同步原語,以及如何在Node.js的主時間循環中與你自身寫的線程進行跨線程通信等。這么一算,Chrome V8、libuv,加上Node.js的C++擴展開發,你相當于一下子買了3本書,是不是覺得很超值?也就是說,你閱讀本書的目的不一定是想要開發Node.js的C++擴展;如果你想學習Chrome V8,或者想學習libuv,也可以參考本書。

本書的最后還簡單展望了一下Node.js 8.0之后出現的一個新特性,就是新一代Node.js C++原生擴展接口N-API。不過由于N-API還處于試驗階段,各種接口還不是很穩定,在未來隨時會變,因此本書中并沒有詳細地介紹N-API,而只是簡單講解了它的思想,讓大家在心中有一個思想準備。這樣,哪一天N-API正式發布了,讀者就可以比較快地上手了。不過,不要忘本,哪怕N-API真的出來了,我還是希望大家多了解一下底層的基礎,比如像Chrome V8、libuv以及Node.js源碼相關的內容。因為學習了這些基礎知識,對大家肯定沒有壞處(甚至對于Node.js,大家說不定會有一個新的認識)。

最后,奉上我在一次技術直播中說過的一句話:“當我們在學習Node.js的時候,我們其實就是在學編程。語言只是最表象的東西,思想才是核心內容。”如果還有部分讀者由于本書需要有C++基礎望而卻步的話,多讀幾遍我剛才說的話,然后鼓起勇氣入“坑”吧。

本書的結構

本書共分為9章。其中前兩章描述了一些基礎的前驅理論知識;第3章到第6章講的是Node.js的C++擴展開發中用到的各種知識,并輔以簡單的樣例;第7章和第8章為實戰章節,根據現實需求來完成相應的Node.js C++擴展;第9章為對未來的N-API的一個展望。

第1章講述了我們在學習本書內容之前所需要了解的基礎,如Node.js的模塊機制與包機制,以及Node.js都是由什么三方依賴構成的。其中就提到了很重要的Chrome V8和libuv。本章的最后還講述了要進行Node.js的C++擴展開發所需要做的準備工作,包括但不限于編輯器的挑選、開發環境的搭建等。

第2章主要講述了什么是Node.js的C++擴展,它的本質是什么,并且什么情況下需要使用C++擴展,以及闡述了為什么在這些情況下要使用C++擴展。

第3章介紹了谷歌的Chrome V8引擎,從它與Node.js的關系講到它的一些基本概念,例如V8的內存機制、基本對象等。在后續的章節中將開始介紹Chrome V8的各種類及其概念,以及它們的用法,如句柄、句柄作用域、模板和各種常用的數據類型等。

第4章相當于各種編程語言書籍中的“Hello World”,向讀者介紹了binding.gyp這個重要的配置文件,以及GYP文件格式的基礎,然后以幾個最簡單的例子向讀者展示了Node.js的C++擴展最簡單的一些代碼,包括函數的參數、回調函數的用法、對象的返回、函數的返回等,以及如何將一個C++的類封裝成Node.js中直接能用的類。

第5章為大家介紹了NAN(Native Abstractions for Node.js)這個非常實用的包,使大家能在不同的Node.js版本(本質上是各不兼容的Chrome V8版本)中使用同一份C++代碼。

第6章講解了如何使用libuv進行異步Node.js的C++擴展代碼編程,首先介紹了libuv的一些基礎概念,如句柄與請求等,然后講述了如何使用libuv進行跨線程編程。

第7章就開始進入了實戰環節。本章通過從零開始寫一個基于C++的文件監視器擴展,講述了要完成一個Node.js原生擴展的一些流程。本章所述的文件監視器源碼地址在https://github.com/XadillaX/node-efsw

第8章與第7章的實戰不同,對兩個現有的簡單C++擴展包進行分析,從另一個角度剖析了一個Node.js的C++擴展包的源碼。

第9章展望了如何使用Node.js的最新特性N-API進行原生擴展的開發。不過我估計等到本書正式上市的時候,第9章已經變成一個僅供參考的章節了。

閱讀本書的注意事項

聲明:我在編寫本書之際,還在大搜車工作,所以書中的很多內容都是基于大搜車的角度來寫的。比如8.2節中有一處內容是這樣的:

在筆者所在公司的內部,用了一套基于Dubbo深度定制的RPC服務框架。Node.js要訪問這些Java服務的RPC函數是通過定制的HTTP協議來完成的,所有的RPC服務節點都到Zookeeper進行注冊。

這里指的公司就是大搜車。再比如2.1.2節中的一段話:

在官方的Node.js版本ONS SDK出來之前,筆者自己造了一個基于其官方C++版本的ONS SDK封裝的輪子,用的當然是本書所講的姿勢——Node.js的C++擴展了。

由于編寫本書時我還并未從大搜車離職,因此這仍然是站在就職于大搜車的角度寫的。

我在編寫本書之際,Node.js的8.x版本并未進入LTShttps://github.com/nodejs/Release#release-schedule.階段。于是我采用了Node.js 6.x作為樣例進行了講解,而Node.js 6.x距離LTS結束也還有一段時間。而且使用本書的方法進行Node.js的原生擴展開發,在Node.js 6.x、Node.js 8.x甚至是Node.js 9.x下都是通用的。本書中的樣例都是基于Node.js v6.9.4進行講解的,讀者在參考的時候上調或者下調幾個中、小版本號問題都不大

至于N-API一章(第9章),我在該章中也曾談道:

本章內容在書中將會一帶而過,因為在筆者寫書的時候,N-API還沒有完全穩定下來,隨時會改變。而且筆者個人認為,距離N-API能正式投入生產用途的時間還很長。所以本章內容在本書中僅以擴展閱讀的形式存在,其實關于N-API的內容在5.1.2節中曾略微提及。

因此,該章內容僅供參考,具體內容應以官方文檔為準。

另外,本書所有的隨書代碼均在macOS命令行下測試通過。理論上,它們也可以在Windows和UNIX上運行良好,但我并沒有驗證過。

最后,給出本書中經常用到的一些地址。

· 本書隨書代碼的Git倉庫:https://github.com/XadillaX/nyaa-nodejs-demo

· Node.js v6.9.4代碼倉庫:https://github.com/nodejs/node/tree/v6.9.4

· Node.js v6.x所對應的Chrome V8文檔:https://v8docs.nodesource.com/node-6.12/。若讀者打開該地址,卻發現頁面不存在,可直接前往https://v8docs.nodesource.com/,并點擊“6.x”字樣的超鏈接進入(注意該地址經常換)。

· 作者的個人技術博客:https://xcoder.in

· 作者的GitHub地址:https://github.com/XadillaX

· Me:https://github.com/XadillaX/me

致謝

感謝我的妻子,她也是一位優秀的Node.js研發工程師。她的支持是對我的最大鼓勵,如果不是她,這本書的問世也許會更晚。

感謝我的父母,在我的背后默默地支持我的事業。在我很小的時候,他們就一直支持我追尋自己的夢想,這才使我能夠在編程領域一路走下來。

感謝我的老東家大搜車,它營造了良好的技術與實踐氛圍,同事(包括領導)給予了我不少幫助,如書中圖示的優化、閱讀體驗的建議等。這些同事有段鵬飛以下名字按字典序排序。、紀清華、劉佳楠、許波、王琦、袁小山……

感謝現實以及社區中的朋友們在本書創作的時候進行試讀和探討,并提供了一些其他幫助,他們包括但不限于Akagi201、ADoyle、David Cai、Hax(賀老)、賀星星、精子(jysperm)、孟德森、天然、五花肉、引證、張秋怡。

感謝為本書寫序和推薦語的作者們:安娜·亨寧森(Anna Henningsen)、曹力(ShiningRay)、顧天騁(Timothy Gu)、桑世龍(狼叔)、雷宗民(老雷)、劉亞中(Yorkie)、迷渡(justjavac)、潘旻琦(pmq20)、田永強(樸靈)、袁鋒(蘇千)、孫信宇(芋頭)、王文睿博士、響馬,你們一直是我們的楷模與學習對象。

感謝我的高中計算機老師兼NOIP集訓教練王震老師,王震老師是我在編程路上的啟蒙老師,沒有他就沒有今天會寫代碼的我;也感謝當時陪我堅持走這一條路到畢業的好隊友jiecchen和MatRush;感謝我的大學ACM教練宣江華老師和一直為集訓隊默默付出的陳萌老師;還要感謝我的研究生導師李啟雷博士傳道受業。

感謝博文視點的劉皎女士以及她的團隊,是他們的努力使本書最終能與廣大讀者見面,他們提出的專業意見給了我很多幫助。

最后,還要特別感謝董偉明(《Python Web開發實戰》作者)。在閱讀了他的一篇文章《寫一本技術書籍》https://zhuanlan.zhihu.com/p/22207407后,我才有了寫作本書的想法,并最終付諸實施。

死月(朱凱迪)

2018年3月于杭州

主站蜘蛛池模板: 衡水市| 郎溪县| 上饶县| 屯昌县| 宝丰县| 南乐县| 明水县| 长武县| 南乐县| 大港区| 黄龙县| 桐庐县| 仙桃市| 石阡县| 武城县| 奈曼旗| 信宜市| 华宁县| 抚顺市| 明光市| 凌云县| 井研县| 繁峙县| 襄城县| 宜城市| 崇信县| 宁津县| 浮梁县| 新化县| 江津市| 哈巴河县| 平遥县| 平定县| 郯城县| 抚州市| 新乡县| 呼图壁县| 中卫市| 青岛市| 梧州市| 荆州市|