聊聊Web程序員所具有的基本技能
前言:同步一篇2017年1月在QQ空間寫的隨筆,2017年,我還在實習(xí),現(xiàn)在回首,已經(jīng)好幾年過去,現(xiàn)在看起來,還挺有意思的。
web相對于其他方向來說,會簡單點,但是涉及的東西會多點,如今的web程序員,所需的基本技能應(yīng)該有三劍客,nodejs,php,mysql,http系列協(xié)議,網(wǎng)絡(luò),瀏覽器基本原理,apache/nginx,其中包括幾十個javascript庫和幾百個框架,沒準(zhǔn)還需要個shell和linux常用命令,如果這些都涉獵過了,沒事,面試人家還會問各種源碼,原理,機制有沒有。不過需要的技能其實很大程度上依賴于公司,具體來說應(yīng)該有這么幾種情況 ,參與小系統(tǒng)或者內(nèi)部系統(tǒng)的開發(fā)時,前端程序員其實就是個web程序員,需要自己建表,寫服務(wù)端邏輯,前端邏輯,寫頁面樣式,交互,俗稱全棧,如果有個后臺和你搭配,或許你可以免去寫后端的代碼。參與中型系統(tǒng)開發(fā)時,前端程序員需要做的是寫交互,頁面和樣式有重構(gòu),前端只需要處理用戶操作然后和后臺搞好接口就行,參加大型系統(tǒng)開發(fā)時,前端程序員還需要寫中間轉(zhuǎn)發(fā)層,因為前端有個同源策略,對于一般的系統(tǒng),整個系統(tǒng)都是由一個團隊負責(zé)的,前后端的代碼再怎么分離,也還是有辦法解決同源問題,但是大型系統(tǒng)的后臺有時候并不是由一個團隊負責(zé)的,這時候,前端看到的就是一個黑盒子,我們只是根據(jù)后臺給的接口,把前端的數(shù)據(jù)傳到我們的后臺,也就是中間層(中間層可以是nodejs或者php來做),然后在后臺去訪問別的后臺,而且后面可能有好幾十個后臺串起來,這時候就沒有什么前端和后臺了,或許叫客戶端和服務(wù)端更加好,利用中間層,我們解決了同源問題,但是中間層不僅僅是為了解決同源問題。現(xiàn)在很多公司的系統(tǒng)都拆成服務(wù)化,比如做一個登錄的子系統(tǒng),然后一大波平臺都統(tǒng)一去那校驗登錄態(tài)。中間層也是為了業(yè)務(wù)的接入。所以,參與開發(fā)的系統(tǒng)不同,所需要的技能也不一樣。
但是,作為web程序員,最核心的應(yīng)該還是javascript,javascript這門語言,套路很深,而且和很多傳統(tǒng)的語言差別很大,無論是鼻祖c語言,還是各種面向?qū)ο蟮恼Z言,我覺得函數(shù)里分配的變量在函數(shù)執(zhí)行完還能被訪問,這個點就很不一樣,javascript的知識點不算是很多,核心的大概有詞法作用域,原型鏈,this問題,bind/call/apply系列函數(shù),閉包,變量提升,正則,函數(shù)是一等公民,變量對象,執(zhí)行上下文,arguments,setTimeout系列函數(shù)等,因為有垃圾回收器,內(nèi)存管理這個大難題我們就不需要過于擔(dān)心了,但是javascript的知識只是前端的其中一部分,接下來的還有BOM和DOM的知識還有API非常多,雖然常用的都不會很難,但是一不小心還是會踩坑,高級點的還有v8的一些知識,包括javascript編譯和執(zhí)行的過程原理,js引擎是單線程,瀏覽器是多線程,事件驅(qū)動模型,事件隊列,頁面加載和渲染原理,瀏覽器的工作原理。
網(wǎng)絡(luò)協(xié)議也是很重要的一部分,應(yīng)用層現(xiàn)在說的基本都是http1.1,https和http2,http2的前身spyd已經(jīng)在chrome里部署,http2目測也要來臨了,不過現(xiàn)在討論比較多的還是https,畢竟安全也是很重要的, http1.1主要需要搞一下rfc文檔和http權(quán)威指南就功力大增了。http協(xié)議的核心知識應(yīng)該有緩存機制,常見的請求方法,cookie機制,持久連接和管道化機制,常見的http響應(yīng)碼,請求頭,響應(yīng)頭的意義。還包括一些安全的,協(xié)議升級協(xié)商,解決跨域的頭部。https協(xié)議的知識包括ssl握手機制和過程,connect方法實現(xiàn)https流量的轉(zhuǎn)發(fā),https服務(wù)器的搭建。http2加了很多高大上的特性,提供了很多新的功能和對http1.1的性能進行了優(yōu)化。tcp/ip,dns協(xié)議也是前端需要學(xué)習(xí)的知識,瀏覽器對域名進行解析或預(yù)解析時需要使用dns協(xié)議。需要了解瀏覽器解析域名的機制,比如瀏覽器里有對域名的解析進行緩存,這會導(dǎo)致使用dns服務(wù)器進行負載均衡時達不到效果,host文件里也有域名的映射,利用host文件可以配置不同的域名指向127.0.0.1來進行同源策略的學(xué)習(xí),然后dns服務(wù)器自然也有緩存或者域名對應(yīng)的ip,最后還需要了解dns服務(wù)器進行域名解析的機制,這些在計算機網(wǎng)絡(luò)里都會說到。tcp/ip協(xié)議里,前端的知識里似乎沒有太多涉及到ip協(xié)議的,tcp卻是很重要的一部分,tcp協(xié)議是ssl和http協(xié)議的基礎(chǔ),后者都是需要在建立tcp連接的基礎(chǔ)上進行工作的,理解tcp協(xié)議對前端的優(yōu)化有很大幫助。
瀏覽器基本工作原理是前端比較重要的一塊,webkit內(nèi)部這本書講了很多這方面的知識,而且也很全面, 瀏覽器工作原理包括域名解析和緩存,tcp連接的管理,cookie管理,同源策略機制,緩存管理,頁面代碼的分析,布局計算,渲染,js引擎和渲染引擎的互斥工作,dom樹和cssom樹的構(gòu)建,dns預(yù)解析,頁面預(yù)渲染,tcp預(yù)連接,其實js引擎是單線程和瀏覽器是多線程這個知識也比較重要,這個對理解為什么大量的cpu密集型的計算會導(dǎo)致瀏覽器掛掉。為什么js引擎正在執(zhí)行代碼時,點擊了按鈕,點擊事件的回調(diào)還可以被會加到事件隊列里。還有setTimeout(0)的原理有很大的幫助。瀏覽器什么時候會進行布局計算和重繪影響我們?nèi)绾螌懘a,以免引起性能問題。輸入url時,瀏覽器發(fā)生了什么,這個面試題基本是前端面試必問??梢姙g覽器的原理也是需要了解的。
代理/web服務(wù)器也是比較重要的一部分,因為大部分的對外系統(tǒng),因為安全,性能等問題,都是有代理的,squid和nginx是比較重要的代理服務(wù)器,squid是緩存代理,是對靜態(tài)資源進行緩存以提高性能,nginx是神器,功能太多,接觸到的都是做反向代理的,nginx的代碼和架構(gòu)都是享有美譽的,看代碼是理解軟件的最好方式,作為一個前端,其實去深入研究nginx代碼或許暫時沒有必要,但是大概看一些工作原理和代碼的設(shè)計架構(gòu),對自己的水平和對nginx的工作原理都是有好處的,tnginx是淘寶基于nginx開發(fā)的一個服務(wù)器,他們把研究的思路和心得都發(fā)布到他們的網(wǎng)站上,有興趣的可以去瞅瞅,理解了nginx的基本工作原理,nodejs和nginx都是用了一種神技,就是事件驅(qū)動模型+單線程,應(yīng)對網(wǎng)絡(luò)高并發(fā)無壓力,和傳統(tǒng)的一言不合就開進程和線程不同,進程線程的切換花銷很大,而且同步互斥問題很復(fù)雜,事件驅(qū)動是通過注冊事件,事件發(fā)生時把回調(diào)扔到事件隊列里去排隊執(zhí)行,單線程就去不斷輪詢事件隊列,執(zhí)行回調(diào),其實js也是這樣。但這種模式不適合cpu密集型的應(yīng)用,因為單線程,傷不起。nginx的功能很多,可以做代理服務(wù)器,也可以做web服務(wù)器(比如配置一個https服務(wù)器),郵件服務(wù)器,緩存服務(wù)器等等,使用nginx主要是需要學(xué)會使用nginx.conf。至于參數(shù)調(diào)優(yōu),開發(fā)自己的模塊,這都是高級話題。說到服務(wù)器,誰敢不說老前輩apache,apache一般作為web服務(wù)器使用,管理靜態(tài)頁面和和后端的cgi程序通信,把前端的請求分配給cgi程序處理,一般使用的是php,apache一般是以一種預(yù)先派生進程/線程的方式工作,這樣前端的請求來的時候,就不需要急忙地創(chuàng)建進程/線程,來一個請求,從線程池里拿出一個進程/線程,所以高并發(fā)會爆,使用apache一般也是熟悉httpd.conf文件,里面包括配置虛擬主機,需要監(jiān)聽的ip和端口,每個目錄的權(quán)限控制,文件權(quán)限控制,url重寫,打log,對靜態(tài)文件進行緩存管理,配置一些http頭,壓縮,加載相應(yīng)的模塊等,和nginx類似但是語法不太一樣。
后端,作為一個前端,有時候也需要知道后端的知識,因為你不知道什么時候你需要去寫后端,學(xué)習(xí)點后端不至于到時候一臉懵逼,后端現(xiàn)在一般是使用nodejs和php,python也有人用,很多人說對于前端來說,學(xué)習(xí)nodejs可能不是很難,但其實也不是這么簡單,至少不會比php簡單,因為對于lamp下的網(wǎng)站,前端發(fā)請求到apache,然后apache把請求扔給php,php處理,最多連個數(shù)據(jù)庫,比較簡單,但是nodejs就不一樣了,因為nodejs是集web服務(wù)器和應(yīng)用服務(wù)器與一身的,你用nodejs可以直接監(jiān)聽一個端口,這就是一個服務(wù)器,不需要像apache和nginx那樣配置什么,然后你前端的請求到nodejs后,nodejs會執(zhí)行相應(yīng)的回調(diào),這里有很多東西需要自己去做,而且nodejs的框架如express基本沒什么功能,需要安裝一大堆中間件去幫你干活。不像php那些框架,什么都幫你做好了,像在php里上傳一個文件,用$_FILES就可以拿到文件的內(nèi)容和信息,在nodejs里你首先要百度一波,然后找一個希望沒把你折磨死的中間件,才能完成這個功能,再比如前端傳的查詢字符串,在php里可以直接根據(jù)鍵值拿到相應(yīng)的值,在nodejs甚至express里,你得到的只是一個字符串,然后你自己去解析,或者你用中間件去解析,在express的早期版本里,前端post一個嵌套了兩層的對象過去,在express里第二層的對象直接變成數(shù)組了,差點沒嚇?biāo)牢遥蚓褪窃缙诘闹虚g件功能還不夠牛逼,所以對于這種框架,除非你牛逼,自己寫中間件,要不然你就是等著那些大牛寫中間件給你用的處境,這只是說一下nodejs的學(xué)習(xí)成本并不低,現(xiàn)在nodejs和相關(guān)的框架已經(jīng)進化得很好,是比較熱門的一個技術(shù),因為nodejs的語法是基于js的,所以也比較適合前端程序員學(xué)習(xí),只是我們在nodejs里,有時候我們可能需要比在php里做的更多。這差不多就是nodejs給我們最原始的玩意,讓我們自己隨心所欲去做我們想做的事情。不像python,能用一句代碼解決的事情,就不要用兩句。nodejs的相關(guān)知識點很多,畢竟功能比較強大,常用的大概包括進程相關(guān)的,文件系統(tǒng)相關(guān)的,處理網(wǎng)絡(luò)請求相關(guān)的,字符串處理相關(guān)的。nodejs的運行原理和架構(gòu)也需要去學(xué)習(xí),因為這樣才能用好用對nodejs。如果使用express的話可以去瞅瞅他的源碼,源碼不是很多,因為他是靠大量的中間件來工作的,其中路由的源碼是比較核心的,路由也是express里很重要的功能,這里的路由不是前端請求最后怎么分發(fā)到具體的業(yè)務(wù)代碼里,指的是對于每一個前端請求,在express里是怎么被處理的。express的路由思想看起來不是很難,不過很有意思,類似于nginx的請求被處理的過程,對于每一個進來的請求,被串行地傳到一個個函數(shù)或者模塊里進行處理,然后決定要傳給下一個還是結(jié)束這個請求,nginx里也是這么一個過程,有點像設(shè)計模式里的責(zé)任鏈模式。最后express里的很多package源碼非常值得研究,在npm官網(wǎng)的里很多源碼包也值得研究,對js的功力提升有很多的幫助。
數(shù)據(jù)庫,前端其實很少會接觸到數(shù)據(jù)庫,基本上就是設(shè)計一些簡單的表,然后進行增刪改查,需要了解一些sql, 對于數(shù)據(jù)庫,其實也是基于一個客戶端,服務(wù)器模型,我們的cgi程序去連接遠端的數(shù)據(jù)庫,也就是進程間的通信,只是有時候是不同的主機間的,連接數(shù)據(jù)庫,基本的參數(shù)是數(shù)據(jù)庫進程所在的主機ip,端口(默認是3306),數(shù)據(jù)庫名,用戶名,密碼。數(shù)據(jù)庫也是一個復(fù)雜的玩意,比如sql的解析和優(yōu)化,連接管理,對數(shù)據(jù)的緩存和管理。
安全也是web程序員很重要的一部分知識,和前端相關(guān)的大概有xss,csrf,點擊劫持,和后端相關(guān)的大概有sql注入,http頭注入,會話劫持,文件上傳。xss主要是提交和顯示的時候需要對內(nèi)容進行轉(zhuǎn)義,csrf主要是利用csrfCode來確認某個請求是否是用戶自愿發(fā)出的,點擊劫持遇到不是很多,有一個方法是引用iframe嵌入第三方網(wǎng)站的界面,然后隱藏自己的界面進行劫持用戶的輸入和點擊。這種可以使用http頭禁止自己的網(wǎng)頁被嵌到別的網(wǎng)頁里,或者在前端代碼里進行判斷跳轉(zhuǎn),后端的安全主要是需要對用戶的輸入進行過濾,會話劫持可以修改php配置文件解決,文件上傳沒有接觸過。前端安全中最重要的應(yīng)該屬于同源策略了,現(xiàn)在增加了很多新特性來防止各種安全問題,包括一些http頭來定義返回的html文檔里資源訪問的限制,和對iframe標(biāo)簽里的文檔進行權(quán)限控制。還有一個是之前比較出名的a標(biāo)簽的target='_blank'的安全問題。
設(shè)計模式也是一個重要的部分,寫代碼一開始是先隨便寫,實現(xiàn)功能第一,漸漸地,就需要開始考慮怎樣寫好代碼,怎么寫比較好,怎么組織比較好,有時候,有些設(shè)計模式的確會很優(yōu)雅地解決一些問題,代碼的重用和可維護性對于自己和別人都是很重要的。提高寫代碼的方法,不僅需要看書學(xué)習(xí),也需要不斷琢磨,思考,還需要不斷地看別人的代碼和一些寫得比較好的源碼。因為如今的前端不再是以前的幾個交互,現(xiàn)在的前端已經(jīng)變得越來越復(fù)雜,所以寫可持續(xù)發(fā)展的代碼變得很重要。
函數(shù)庫,框架和軟件是用來提高工作和學(xué)習(xí)效率的,web程序員的常用軟件大概有fiddler神器,wireshark神器,whistle還有瀏覽器f12出來的各種tab,隨著瀏覽器原生地支持很多功能,有些庫的功能可能會漸漸變得沒必要,現(xiàn)在各大公司已經(jīng)漸漸放棄作死的ie,不再支持8以下的版本,很多兼容性問題漸漸也會消失。剩下的一堆打包壓縮工具就沒啥好說的了。
工作其實最主要的技能是學(xué)習(xí)能力和解決問題能力,學(xué)習(xí)能力是必不可少的,學(xué)習(xí)一個新東西時,首先看他的文檔先使用它,然后再看他的源碼,因為這樣才能真正了解他的本質(zhì),這是有必要的,即使像nodejs的源碼,雖然不可能完全看懂,但是大致的脈搏還是需要摸清一下的,至少我覺得這樣用起來才會安心,舒服。當(dāng)擁有一定的知識后,遇到問題怎么解決,這也是一個重要的部分,控球好的人不一定就會過人,做一個需求,有時候可能只是改一點點東西,但是在哪改,改完會不會對之前的功能有影響。所以改一點點東西的需求,首先你要去看別人的一堆代碼,而這堆代碼還不一定是在同一個地方,甚至不在一個系統(tǒng)里, 但是這種問題始終需要解決,但這種困難就像看英文文檔一樣,一開始是會很痛苦,但是慢慢地,你就會習(xí)慣這種情況,并且潛移默化中提升了自己的能力。還有一種需求是開發(fā)一個完全新的功能,這時候你不需要看別人的代碼了,所以這時候你就可以考慮,琢磨你該如何組織和編寫自己的代碼,使得看起來很舒服,維護和擴展也很容易,這無形中又提高了自己,工作的勞累和壓力其實不僅僅來源于工作本身的內(nèi)容,更來源于你無時無刻都需要思考,很多事情,只有細細考慮,慢慢琢磨才能做好,做對,這會大量消耗你的腦力,所以做技術(shù)費腦,有時候并不一定是說你要多聰明,而是你要一直保持你大腦的效率和清晰。
最后想說的是,其實做技術(shù)還是需要找到自己的興趣和方向,抓住重點去 學(xué)習(xí),現(xiàn)在技術(shù)更新太快,枝繁葉茂,難免會有點方,但是還是需要按照自己的計劃慢慢去學(xué),不需要太急躁!多去學(xué)一些本質(zhì)的知識,因為只有這些是不會變的,比如es6的class,其實只是一種語法糖,他的背后也還是以前的原型鏈知識。現(xiàn)在的開源社區(qū)非?;钴S,你在上面其實會發(fā)現(xiàn)很多很好的代碼和很厲害的人,但是我覺得應(yīng)該學(xué)習(xí)他們,而不是給自己不好的心理壓力。蘇軾說的對,早年讀書無甚解,晚年省事有奇功,學(xué)習(xí)的時候,很多東西你覺得沒用的,其實在一定程度上他已經(jīng)提高了你。