JavaScript框架的四個時代

前端小智發表於2022-07-04

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

本文為譯文,原作者是 Chris ,它是Bitski的首席前端工程師,Ember.js核心團隊成員,曾任LinkedIn、Addepar、Ticketfly(現為EventBrite)的前端工程師,反正是個厲害大佬就是了,本文的第一人稱都指是的該大佬。

早在2012年,我開始主要用JavaScript進行編碼。我曾為一家本地企業從頭到尾做了一個PHP應用,一個基本的CMS和網站,公司決定要重寫它並增加一些功能。

專案經理希望我使用.NET,部分原因是這是他所知道的,但也因為他希望這個應用感覺像一個本地應用程式--沒有頁面重新整理或操作動作長時間等待。經過一番研究和原型設計,我說服了經理,可以使用當時剛開始出現的全新JS框架,它能做到這些事項。

我選擇的第一個框架實際上是 Angular 1。在我遇到路由器的一些問題之前,已經建立了一個相當大的應用程式,並使用FuelPHP的後端--每當重新渲染子路由/出口時,它就會閃爍,而且真的感覺它在設計時沒有考慮到這種場景。

後面,有人向我推薦了Ruby on Rails + Ember,在試過之後,覺得效果很好。我也喜歡這兩個框架的理念,喜歡這些社群生態,而且與當時的替代方案相比,總的來說,它非常有成效。

從那時起,很多事情都發生了變化--框架層出不窮,並且有了很大的發展。去無可以在瀏覽器中用JavaScript構建應用程式的想法,從某種程度上的邊緣變成了一種標準做法。我們構建的基礎設施已經完全改變,實現了一系列新的可能性。

在這段時間裡,各種想法之間也有相當多的競爭和衝突。使用哪種JavaScript框架,如何編寫CSS,函數語言程式設計與物件導向程式設計,如何最好地管理狀態,哪種構建系統或工具最靈活、最快速,等等。回顧過去,這些覺得很有趣,我們經常爭論的是錯誤的事情,而忽略了一些前瞻性,當然,這也是事後諸葛亮。

所以我想做一個回顧,回顧過去幾十年的JavaScript開發,看看我們已經走了多遠。我們可以把它大致分為四個主要時代。:

  • 原始年代
  • 第一個框架
  • 以元件為中心的檢視層
  • 全棧式框架

每一個時代都有自己的主題和核心矛盾,同時也都想到吸取關鍵教訓,並穩步前進。

今天,爭論仍在繼續。web 是否變得過於臃腫?一般的網站真的需要用React編寫嗎?我們甚至應該使用JavaScript嗎?當然,當前也不能代表未來,未來現有框架很大可能也會被替換,但是,也是從現有的一些觀點出來,幫助我們向前邁進。

原始年代

JavaScript是在1995年首次釋出的。就像我上面提到的,我是在2012年開始寫JS的,差不多20年後,接近我稱之為第一框架的時代的開始。你可以認為,我在這裡可能會掩蓋很多歷史,而且這個時代可能會被分解成許多子時代,每個時代都有自己的模式、庫和構建工具等等。

也就是說,我不能寫我沒有經歷過的事情。當我開始編寫前端應用程式時,新一代的框架剛剛開始走向成熟。Angular.js、Ember.js、Backbone,等等。

在這之前,最先進的技術是jQuery和MooTools等庫。這些庫在它們的時代非常重要--它們幫助平滑了瀏覽器實現JavaScript的方式之間的差異,這些差異是非常重要的。

例如,IE 實現事件的方式與Netscape完全不同--冒泡事件與捕獲事件。這就是為什麼我們今天的標準最終實現了這兩種方式,但在這之前,我們需要使用庫來編寫能在兩種瀏覽器上使用的程式碼。

這些庫主要用於製作小型的、獨立的使用者介面元件。大多數應用程式的業務邏輯仍然是通過表單和標準的HTTP請求進行的--在伺服器上渲染HTML並將其提供給客戶端。

在這個時代也沒有什麼構建工具可言,至少我知道的是。當時的JavaScript還沒有模組(至少沒有標準的模組),所以沒有任何辦法匯入程式碼。所有的東西都是全域性性的,要組織好這些東西是非常困難的。

在這種環境下,可以理解的是,JS通常被視為一種玩具語言,而不是你用它來寫一個完整的應用程式。那時我們最常做的事情是加入 jQuery,為一些UI小部件編寫一些指令碼,然後就可以了。

隨著時間的推移和XHR的引入和普及,人們開始把他們的UI流程的一部分放到一個頁面中,特別是對於需要在客戶端和伺服器之間進行多次來回互動的複雜流程,但應用程式的大部分內容還是留在伺服器上。

這與移動應用開始出現時的情況形成了鮮明的對比。從一開始,iOS和Android上的移動應用就是用Objective C和Java等嚴肅語言™編寫的完整應用。此外,它們是完全由API驅動的--所有的UI邏輯都在裝置上,與伺服器的通訊純粹是資料格式的。這導致了更好的使用者體驗和移動應用的爆炸性增長,直接導致了我們今天關於移動和 web 哪個更好的爭論。

用JavaScript做這一切,起初被認為是可笑的。但隨著時間的推移,應用程式開始變得更加雄心勃勃。社交網路增加了聊天、DM和其他實時功能,Gmail和Google Docs表明可以在瀏覽器中編寫相當於桌面應用,越來越多的公司轉向編寫 web應用,因為 web 在任何地方都可以工作,而且更容易長期維護。這推動了整個行業的發展--現在很明顯,JS可以用來編寫非簡單的應用程式。

當時的JavaScript還沒有今天的所有功能,所有的東西都是全域性的,通常需要手動下載並將每個外部庫新增到靜態資料夾中。當時還沒有NPM,模組也不存在,JS也沒有今天一半的功能。

在大多數情況下,每個應用程式都是定製的,每個頁面都有不同的外掛設定,每個外掛都有不同的系統來管理狀態和渲染更新。為了解決這些問題,最早的JavaScript框架開始出現了。

第一個框架

大約在2000年代末和2010年代初,第一批專門用於編寫完整客戶端應用程式的JS框架開始出現。這個時代的幾個有名的框架:

  1. Backbone.js
  2. Angular 1
  3. Knockout.js
  4. SproutCore
  5. Ember.js
  6. Meteor.js

當然,還有很多其他的,可能還有一些在某些圈子裡更大的。這些是我記得的,主要是因為小明用它們來編碼,而且它們比較受歡迎。

這是一代框架,正在進入未知的領域。一方面,他們試圖做的事情是非常雄心勃勃的,而且很多人認為它永遠不會真正成功。

有許多反對者認為單頁JS應用程式(SPA)從根本上來說更糟糕,而且在很多方面他們是對的--客戶端渲染意味著機器人不能輕易抓取這些頁面,而且使用者甚至需要等待幾秒鐘才能開始繪製應用程式。很多這些應用程式都是無障礙的噩夢,如果關閉了JavaScript,它們就根本無法工作。

另一方面,我們沒有在JS中構建完整應用程式的經驗,因此有大量關於最佳方法的競爭性想法。大多數框架都試圖模仿其他平臺上的流行做法,所以幾乎所有的框架最後都是Model-View-*的某種迭代。Model-View-ControllerModel-View-ProducerModel-View-ViewModel等等。但從長遠來看,這些都不是真正意義上的成功--它們並不特別直觀,而且很快就變得非常複雜。

這也是一個我們真正開始嘗試如何編譯JavaScript應用程式的時代。Node.js在2009年釋出,NPM在2010年緊隨其後,為(伺服器端的)JavaScript引入了包。

CommonJS和AMD爭奪如何最好地定義JS模組,而像Grunt、Gulp和Broccoli這樣的構建工具則爭奪如何將這些模組組合成一個可交付的最終產品。

在大多數情況下,這些都是非常通用的任務執行器式的工具,它們真的可以構建任何東西,只是碰巧要構建JavaScript--還有HTML、CSS/SASS/LESS,以及其他許多進入web應用的東西。

然而,我們從這個時代學到了很多東西:

  • 基於URL的路由是基礎。沒有這種路由的應用程式會破壞 web,因此需要在框架中從一開始就考慮到這一點。
  • 通過模板化語言擴充套件HTML是一個強大的抽象層。即使它有時會有點笨拙,但它使使用者介面與狀態保持同步變得更加容易。
  • SPA的效能很差,而且web有許多原生應用所沒有的額外限制。我們需要通過 web 釋出所有的程式碼,讓它JIT,然後執行來啟動我們的應用程式,而本地應用程式已經下載和編譯,這是一項艱鉅的任務。
  • 作為一種語言,JavaScript有很多問題,它確實需要被改進,以使事情變得更好--框架無法單獨做到這一點。
  • 我們絕對需要更好的構建工具、模組和包裝,以便大規模地編寫應用程式。

總的來說,這個時代是富有成效的。儘管有缺點,但隨著應用程式的複雜性增加,將客戶端與API分離的好處是巨大的,而且在許多情況下,所產生的使用者體驗是驚人的。如無特殊情況,這個時代可能會繼續下去,我們到現在還在迭代MV*風格的想法。

但後來一顆小行星突然出現,把現有的正規化砸得四分五裂,造成了一次小規模的滅絕事件,把我們推進了下一個時代--這顆小行星名叫React

以元件為中心的檢視層

我不認為React發明了元件,但說實話,我也不太清楚它們最早來自哪裡。但至少可以追溯到.NET中的XAML,而 web 元件也在那時開始作為一種規範發展。最終它並不重要——一旦這個想法出現了,每個主要的框架都很快地採用了它。

事後看來,這完全是有道理的--擴充套件HTML,減少長期存在的狀態,將JS業務邏輯直接與模板繫結(無論是JSX還是Handlebars還是Directives)。

基於元件的應用程式消除了完成工作所需的大部分抽象概念,並且明顯地簡化了程式碼的生命週期--一切都與元件的生命週期而不是應用程式的生命週期聯絡在一起,這意味著作為一個開發人員,你要考慮的事情要少得多。

然而,當時還有一個轉變:框架開始把自己吹噓成 "檢視層",而不是成熟的框架。他們不再解決前端應用所需的所有問題,而是專注於解決渲染問題。

其他問題,如路由、API通訊和狀態管理,則由使用者自己決定。這個時代著名的框架有:

  1. React.js
  2. Vue.js
  3. Svelte
  4. Polymer.js

還有很多其他的。現在回過頭來看,我認為這是第二代框架的一個流行框架,因為它確實做了兩件主要的事情。

  1. 它極大地縮小了範圍。該框架的核心不是試圖在前期解決所有這些問題,而是專注於渲染,許多不同的想法和方向可以在更廣泛的生態系統中探索其他功能。有很多糟糕的解決方案,但也有很好的解決方案,為下一代從精華中挑選最好的想法鋪平了道路。
  2. 這讓我們更容易接受它們。採用一個完整的框架來接管你的整個網頁意味著重寫你的大部分應用程式,這對於現有的伺服器端巨石來說是不可能的。使用像React和Vue這樣的框架,你可以一次一個小部件或元件地將它們的一小部分放入現有的應用程式中,允許開發人員增量地遷移他們現有的程式碼。

這兩個因素導致第二代框架迅速發展,使第一代框架黯然失色,從遠處看,這一切似乎很有意義,是一種合理的演變。但在當時身處其中,是相當令人沮喪的經歷。

首先,當我們在工作中爭論使用哪種框架,或者是否應該重寫我們的應用程式時,並不經常遇到這樣的框架。相反,很多時候是 "它更快!"或 "它更小!"或 "它是你所需要的一切!"。

還有關於函數語言程式設計和麵向物件程式設計的辯論,很多人把FP作為我們所有問題的解決方案。公平地說,這些事情都是真的。僅有檢視層的框架更小(起初)、更快(起初),而且是你所需要的全部(如果你自己建立或縫合了很多東西)。

當然,函數語言程式設計模式解決了大量困擾JavaScript的問題,我認為平均而言,JS因為它們而變得更好。

然而,現實是根本就沒有什麼靈丹妙藥。應用程式仍然龐大、臃腫和複雜,狀態仍然難以管理,路由和SSR等基本問題仍然需要解決。

對於我們中的很多人來說,人們想要的似乎是放棄試圖解決所有這些問題的解決方案,而換成一個讓讀者自己去解決的解決方案。

根據我的經驗,這也是工程小組的普遍做法,他們會很高興地接受這種改變,以便交付一個新的產品或功能,然後又不資助完全開發所有這些額外功能所需的時間。

其結果是圍繞這些檢視層建立的自制框架,而這些框架本身是臃腫的、複雜的,而且非常難以操作。

我認為人們在使用SPA時遇到的許多問題都來自於這種分散的生態系統,而這種生態系統恰恰是在SPA使用爆炸性增長的時候出現的。我仍然經常遇到一個新的網站,它不能正確地做路由或很好地處理其他小細節,這絕對是令人沮喪的。

但另一方面,現有的第一代全服務框架在解決這些問題方面也做得不是很好。部分原因是由於大量的技術債務包袱。第一代框架是在ES6之前,在模組之前,在Babel和Webpack之前,在我們弄清楚許多事情之前建立的。

迭代進化是非常困難的,而且完全重寫它們,就像Angular對Angular 2所做的那樣,扼殺了他們社群的發展勢頭。

因此,當涉及到JavaScript框架時,開發人員處於兩難境地--要麼選擇一個開始顯示其年齡的一體化解決方案,要麼跳入自由競爭中,DIY一半的框架,希望得到最好的結果。

當時這讓人非常沮喪,但最後還是產生了大量的創新。隨著這些框架找出它們的最佳實踐,JavaScript生態系統的發展非常迅速,還發生了一些其他的關鍵變化。

  • 像 Babel 這樣的轉譯器成為常態,並有助於使語言現代化。與其等待多年的功能標準化,不如今天就能使用,而語言本身也開始以更快、更迭代的速度增加功能。
  • ES模組被標準化,使我們最終開始圍繞它們構建現代構建工具,如Rollup、Webpack和Parcel。基於匯入的 bundling 慢慢成為規範,即使是樣式和圖片等非JS資源也是如此,這極大地簡化了構建工具的配置,使它們變得更精簡、更快速、更全面。
  • 隨著越來越多的API被標準化,Node和 web 標準之間的差距也在緩慢但穩步地縮小。SSR開始成為一種真正的可能性,然後是每個嚴肅的應用程式都在做的事情,但每次都是一種定製的設定。
  • 釋放了Edge Computing,為基於JavaScript的伺服器應用程式提供了SPA在分佈/響應時間方面的好處(Spas以前由於在CDN上是靜態檔案,因此通常可以更快地開始載入載入,即使它們花了更長的時間才能完全載入並在結束)。

在這個時代結束的時候,一些問題仍然存在。狀態管理和響應性仍然是(現在也是)棘手的問題,儘管我們有比以前更好的模式。

效能仍然是一個困難的問題,儘管情況正在改善,但仍然有很多很多臃腫的SPA在那裡。

可訪問性的情況也有所改善,但對於許多工程機構來說,它仍然經常是一個事後的想法。但這些變化為下一代框架鋪平了道路,我想說的是,我們現在正在進入下一代框架。

全棧式框架

就我個人而言,上一個框架時代真的悄悄來臨了。我想這是因為我在過去4年左右的時間裡深入到Ember渲染層的內部,試圖解決前面提到的影響它作為第一代框架的技術債務(仍然)。但這也是因為它更加微妙,因為所有這些第三代框架都是圍繞上一代的檢視層框架建立的。這些框架包括:

  1. Next.js (React)
  2. Nuxt.js (Vue)
  3. Remix (React)
  4. SvelteKit (Svelte)
  5. Gatsby (React)
  6. Astro (Any)

這些框架是隨著檢視層的成熟和鞏固而開始的。既然我們都同意元件是建立在核心基礎之上的,那麼開始標準化應用程式的其他部分--路由器、構建系統、資料夾結構等,就很有意義了。

慢慢地,這些元框架開始建立起與第一代多合一解決方案開箱即用的相同功能,從各自的生態系統中挑選最佳模式,並隨著它們的成熟而將其納入。

然後他們又進一步。

在這之前,SPA一直只專注於客戶端。SSR是每個框架都希望解決的問題,但只是作為一種優化,一種獲得渲染的方式,最終會在數兆位元組的JS最終載入完畢後被取代。

只有一個第一代框架敢於想得更遠,即Meteor.js,但它同構JS的想法從未真正實現。

但隨著應用程式的規模和複雜性的增加,這個想法被重新審視。

我們注意到,將後端和前端搭配在一起實際上是非常有用的,這樣你就可以做一些事情,比如為某些請求隱藏API祕密,在返回頁面時修改標頭檔案,代理API請求。隨著Node和Deno實現了越來越多的 web 標準,伺服器端JS和客戶端JS之間的差距每年都在縮小,它開始看起來畢竟不是一個瘋狂的想法。將其與 edge-computing和驚人的工具結合起來,就會有一些令人難以置信的潛力。

最新一代的框架充分利用了這種潛力,將客戶端和伺服器無縫地融合在一起,我無法強調這種感覺有多麼令人驚訝。在過去9個月與SvelteKit的合作中,我不知道有多少次坐下來對自己說:"這就是我們應該一直做的事情。"

以下是我最近遇到的一些任務,通過這種設定,這些任務變得異常簡單。

  • 將伺服器端的OAuth新增到我們的應用程式中,這樣認證令牌就不會離開伺服器,同時還有一個API代理,在向我們的API傳送請求時新增令牌。
  • 將某些路由直接代理到我們的CDN,這樣我們就可以託管在任何其他框架中構建的靜態HTML頁面,允許使用者製作自己的定製頁面(我們為一些客戶提供的服務)。
  • 當我們需要使用一個需要密匙的外部服務時,新增幾個不同的一次性API路由(不需要為我們的API新增一個全新的路由並與後端人員協調)。
  • 將我們對LaunchDarkly的使用轉移到伺服器端,這樣我們就可以載入更少的JS,從而降低整體成本。
  • 通過後端路由代理我們的Sentry請求,這樣我們就可以捕捉到由於廣告遮蔽器而未被報告的錯誤。

而這僅僅是冰山一角。這種模式真的有很多很酷的地方,其中最大的一點是它如何重振漸進式增強的理念,利用伺服器和客戶端的組合特性,允許客戶端在使用者禁用JavaScript的情況下回退到基本的HTML + HTTP。

當我開始從事SPA工作時,我自己已經完全放棄了這種做法,認為它們是未來的趨勢,但我們有可能看到它捲土重來的世界,這真的很酷。

這些是新的功能,從經驗上看,我把這些框架歸為新一代的框架。以前難以解決或不可能解決的問題現在變得微不足道,只需改變一點點的響應處理邏輯。

可靠的效能和使用者體驗是開箱即用的,不需要任何額外的配置。我們不需要建立整個新的服務,而是能夠根據需要新增一些額外的端點或中介軟體。這已經改變了生活。

我認為這一代也解決了第一代和第二代框架及其使用者之間的一些主要矛盾點。

它始於向零配置術語的轉變,但我認為它最終是由圍繞第二代框架的生態系統的成熟和穩定所驅動的,這也是一種文化轉變。

第三代框架現在正試圖再次成為一體化的解決方案,試圖解決我們作為前端開發者需要解決的所有基本問題--不僅僅是渲染。

現在比以往任何時候都感覺到社群在解決所有困擾SPA的許多問題方面是一致的,而且重要的是,共同解決了這些問題。

我們接下來要去哪裡?

總的來說,我認為JavaScript社群正朝著正確的方向發展。我們終於開發出了成熟的解決方案,可以從頭開始構建完整的應用程式,這些解決方案並不是 "僅僅是一個檢視層"。

我們終於開始與原生應用的SDK在同一起跑線上競爭,提供一個開箱即用的完整工具包。

我們在這方面仍有很多工作要做。在SPA領域,可訪問性長期以來一直是一個事後的想法,而在GraphQL之外,我仍然認為 data story 可以使用一些工作(不管你喜歡與否,大部分的 web 仍然執行在REST上)。

但趨勢是正確的,如果我們繼續朝著共享解決方案的方向發展,我認為我們可以用比以前更好的方式解決這些問題。

我還對將這些模式進一步提升到 web平臺本身背後的潛力感到興奮。Web元件仍在悄悄地迭代,致力於解決SSR和擺脫全域性註冊等問題,這將使它們與這些第三代框架更加相容。

在另一個方向,WebAssembly可以以一種令人難以置信的方式迭代這種模式。想象一下,能夠用任何語言編寫一個全棧框架。

同構的Rust、Python、Swift、Java等語言最終可以將前臺和後臺之間的障礙減少到幾乎為零--只是在你的系統邊緣有一點HTML模板(這諷刺地使我們幾乎繞了一圈,儘管有更好的使用者體驗)。

我在這裡最大的希望是,我們正在走過碎片化的時代,走過每天都有新的JS框架的時代。自由和靈活孕育了創新,但它們也導致了 web 體驗的混亂、不連貫,而且常常是根本性的破壞。

當開發者不得不在50多個選項中做出選擇,並在有限的資源和緊迫的期限內將它們拼湊在一起時,這就是我們看到的體驗,這也是合理的。一些應用程式非常快速、一致、可靠,使用起來也很有趣,而另一些則令人沮喪、困惑、緩慢和破損。

如果我們能給開發者提供更容易使用的工具,預設地做正確的事情,也許一般的網站會變得更好一些,一般的體驗會更順暢一些。

它不會修復每個網站--沒有多少程式碼可以解決糟糕的使用者體驗設計。但它會奠定一個共同的基礎,所以每個網站開始時都會好一點,每個開發人員都有更多的時間專注於其他事情。

編輯中可能存在的bug沒法實時知道,事後為了解決這些bug,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

作者:Chris 譯者:小智 來源:pzuraq

原文:https://www.pzraq.com/blog/fo...

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章