前端框架:解決方案還是臃腫的問題?
已發表: 2022-03-11現代前端框架要求您在嘗試在瀏覽器上查看之前下載開發環境、完成依賴項並編譯代碼。 這是一件好事嗎? 問題是我們正在構建更複雜的網站,還是框架本身就很複雜,引入了不必要的複雜程度?
自 90 年代以來,今天的 Web 開發已經發展了很多。 我們能夠創造出非常接近任何原生應用程序的完整體驗,並且開發過程也發生了變化。 成為前端 Web 開發人員只需打開記事本、輸入幾行代碼、在瀏覽器上檢查並將其上傳到 FTP 文件夾的日子已經一去不復返了。
過去的前端 Web 開發
我必須首先說明一個顯而易見的事實:世界不像 10 年前那樣。 (震驚,我知道。)唯一不變的就是變化。 過去,我們的瀏覽器很少,但存在很多兼容性問題。 今天,您很少看到“在 Chrome 43.4.1 上觀看效果最佳”之類的內容,但在當時,這很常見。 我們現在有更多的瀏覽器,但兼容性問題更少。 為什麼? 因為jQuery 。 jQuery 滿足了擁有一個標準的通用庫的需求,它允許您編寫操作 DOM 的 JavaScript 代碼,而無需擔心它如何在每個瀏覽器和每個瀏覽器的每個版本上運行——這是 2000 年代真正的噩夢.
現代瀏覽器可以將 DOM 作為標準來操作,因此近年來對此類庫的需求已大大減少。 不再需要jQuery,但我們仍然可以找到許多非常有用的插件依賴於它。 換句話說,Web 框架可能不是必需的,但它們仍然足夠有用,可以流行和廣泛使用。 這是大多數流行的 Web 框架的共同特徵,從 React、Angular、Vue 和 Ember 到像 Bootstrap 這樣的樣式和格式化模型。
為什麼人們使用框架
在 Web 開發中就像在生活中一樣,擁有一個快速的解決方案總是很方便的。 你以前用 JavaScript 做過路由器嗎? 當你可以 npm-install 一個前端框架來克服這個問題時,為什麼還要經歷痛苦的學習過程呢? 當客戶想要昨天完成的事情,或者您從其他開發人員那裡繼承為特定框架設計的代碼,或者如果您正在與已經使用給定框架的團隊集成時,時間就是一種奢侈。 讓我們面對現實吧——框架的存在是有原因的。 如果對他們沒有好處,就沒有人會使用它們。
那麼使用 Web 開發框架有哪些好處和獨特的屬性呢?
時間就是金錢。 當你在開發一個項目時,客戶並不關心你使用哪個框架——實際上,可能甚至不知道你使用的是什麼——他們只關心得到結果,而且越快越好。 已建立的框架可讓您從一開始就立即創建進度感,這是客戶從第一天開始就渴望的。此外,您開發得越快,您賺的錢就越多,因為框架騰出的時間可以重新用於承擔更多項目。
這一切都與社區有關。 在選擇框架時,這是非常重要的一點——當你遇到問題時,誰來幫助你? 你和我都知道它會在某個時候發生。 您將到達需要做一些框架不打算做的事情的地方,或者框架從未設計為讓您訪問的地方,因此有一個支持您的社區是必不可少的。 開發——尤其是自由職業者——可能很難,因為你沉浸在一個虛擬世界中,如果你是團隊中唯一的前端 Web 開發人員,這意味著你是唯一一個有經驗和專業知識的人可以找到一個解決方案。 但是,如果您使用的前端框架有可靠的支持,那麼在世界的另一端就會有人面臨同樣的問題並且可能能夠幫助您。
標準是美麗的。 你有沒有註意到,當你查看自己的一段舊代碼時,你可以很容易地瀏覽它? 或者至少,比其他人編寫的一段代碼更容易? 你以某種方式思考,你有自己的方式來命名事物和組織代碼。 這是一個標準。 我們都追隨他們,即使他們只是為了我們自己。 我們傾向於在早餐時吃類似的東西,在特定的時間醒來,每天把鑰匙放在同一個地方。 事實上,如果我們每天都改變我們的日常生活,那麼僅僅因為弄清楚如何做事的開銷,生活就會變得更加艱難。 曾經因為將鑰匙放在與平常不同的地方而丟失了鑰匙嗎? 標準讓生活更輕鬆。 當作為團隊或開發人員社區的一部分工作時,他們變得絕對不可或缺。
框架從您安裝它們的那一刻起就提供了一個標準,指導您以特定的方式思考和編碼。 您無需花時間與您的團隊一起制定標準; 您可以按照框架中的操作方式進行操作。 這使得一起工作更容易。 當您知道函數必須在某個文件中時,查找函數會更容易,因為它是為在 SPA 中添加路由而構建的,並且在您的框架中,所有路由都放在具有該名稱的文件中。 如果你有這種標準化水平,具有不同技能水平的人可以一起工作,因為雖然高級編碼人員知道為什麼要這樣做,但即使是初級開發人員也可以遵循標準本身。
當框架失敗時
幾年前,如果說“我不使用框架——我看不出它們有什麼真正的好處”之類的話,就會把拿著火把和乾草叉的人帶到你家門口。 但是今天,越來越多的人在問自己,“我為什麼要使用框架? 我真的需要它們嗎? 沒有它們,編碼有那麼難嗎?”
我當然是其中之一——我從來都不是任何特定框架的粉絲,而且在我的整個職業生涯中,我一直在沒有它們的情況下進行編碼。 如果我在這件事上可以選擇,我的選擇總是,“不,謝謝。” 多年來,我一直在使用 JavaScript 進行開發,在此之前,我一直在使用 ActionScript。 當大多數人已經認為它已死時,我正在使用 Flash 進行編碼。 (我知道,我知道……但我做了很多動畫,而純 HTML 的動畫很難。)因此,如果您是眾多從未考慮過沒有框架進行編碼的人之一,那麼讓我向您展示一些您可能會這樣做的原因掙扎。
“一刀切”是謊言。 你能想像編寫一個軟件來完成你在職業生涯中所做的一切嗎? 這是 Web 開發框架的主要問題之一。 您的項目有非常具體的需求,我們傾向於通過添加庫、插件或附加組件來擴展框架的範圍來解決這些需求。 沒有框架能 100% 提供你需要的東西,也沒有框架是 100% 由你會發現有用的東西組成的。
有太多不使用的代碼會導致網站的加載時間滯後,這對於每個額外的用戶來說變得更加重要。 另一個問題是“一刀切”的心態會導致代碼效率低下。 舉個例子, $('sku-product').html('SKU 909090');
, 這是 jQuery 代碼,我們都知道最終會被翻譯成類似document.getElementById('sku-product').innerHTML = 'SKU 909090';
.
單行上的這種差異似乎並不重要,但更改頁面特定元素的內容正是 React 的優點。 現在,React 完成了創建 DOM 表示並分析您嘗試呈現的內容的差異的過程。 從一開始就定位您想要更改的內容不是更容易嗎?
你走過的那團雜草正在長出荊棘。 你有沒有遇到過這樣的情況,你正在使用你的框架並試圖向它添加一個庫,只是意識到你需要的庫版本不能很好地與你正在使用的框架版本一起工作? 有時,讓兩段代碼一起工作比自己編寫代碼需要更多的努力。 而且由於您使用的框架和庫通常構建在其他框架和庫上,這些框架和庫可能隱藏著您甚至無法預料的不兼容問題,因此問題可能會呈指數級增長,達到無法管理的程度希望項目繼續發展。
跟上瓊斯是一回事。 曾經在 AngularJS 中工作過一個項目,卻發現您需要一些在 Angular 4 發布之前才出現的東西? 你甚至知道 Angular 5 已經發布了嗎? 這是另一個大問題。 即使你堅持使用單一的前端框架,當一個新的主要版本發生時,事情可能會發生很大變化,以至於你努力製作的代碼甚至無法在新版本上運行。 這可能會導致任何事情,從需要對大量文件進行的煩人的小改動到完全重寫代碼。
跟上框架的最新版本具有挑戰性,但同樣,當更新完全停止並且無法跟上其餘技術時,其他框架會受到影響。 2010 年,AngularJS 和 Backbone 都首次發布。 今天,Angular 已經發布了它的第五個主要版本,而 Backbone 完全不在聚光燈下。 七年似乎很長。 如果您建立網站,它們的美學和功能可能已經完全改變。 如果你正在構建一個應用程序,押注錯誤的框架可能會使公司在以後需要重寫時陷入艱難且昂貴的境地。
當你只有一把錘子時,一切看起來都像釘子。 如果您經常使用 Web 開發框架,那麼您可能遇到過這種情況,其中單個代碼庫定義了您將來使用的代碼的形狀,即使它只是外圍相關的。 假設您要構建一個像 YouTube 這樣的平台,並且您想使用 Framework X。可能有一點,即使在這個時代聽起來很荒謬,您還是決定使用 Flash 來製作視頻,因為這就是結果內置於框架中。
框架有意見,而且很強大; 例如,React 強制您以特定方式使用 JSX。 您可以在任何地方看到以這種方式使用的代碼。 有替代方案嗎? 是的。 但誰使用它? 這並不總是一件壞事,但如果你需要執行複雜的動畫,你可能只需要一個動畫框架而不是整個 React。 我見過人們做一些瘋狂的事情,比如將 jQuery 添加到頁面只是為了將節點附加到元素,這可以在 vanilla JS 中通過document.getElementById('id_of_node').appendChild(node);
完成。 .
Eval 是邪惡的,但.innerHTML
是馬基雅維利式的
我想花時間單獨探討這一點,因為我認為這是更多人不編寫沒有框架的代碼的原因之一。 當您看到大多數代碼在嘗試向 DOM 添加內容時是如何工作的時,您會發現.innerHTML
屬性注入了一堆 HTML。 我們似乎都同意eval
不利於運行 JavaScript 代碼,但我想在這裡將.innerHTML
放在聚光燈下。 當您將 HTML 代碼作為純字符串注入時,您可能會丟失對您創建的任何節點的任何引用。 確實,您可以通過使用getElementsByClassName
或為它們分配一個id
來取回它們,但這不太實際。 當嘗試更改其中一個節點的值時,您會發現自己又重新渲染了整個 HTML。
當您開始編碼時,這很好。 無需太多經驗,您就可以輕鬆做出很多簡單的事情。 問題出現在現代網站的複雜性上,它往往更像應用程序——這意味著我們需要不斷地改變節點的值,如果你通過重新連接整個結構來做到這一點,這是一項高成本的操作通過.innerHTML
。 React 通過影子 DOM 有效地解決了這個問題,而 Angular 通過使用綁定作為修改頁面上顯示的值的簡單方法來解決這個問題。 但是,通過跟踪您創建的節點並保存將在變量中重用或更新的節點,也可以相當容易地解決它。 通常還有其他原因遠離.innerHTML
。

關於沒有框架的編碼的最大神話
時間就是金錢。 是的,我把這個概念從早些時候帶回來了。 很多人覺得,如果他們停止使用流行的 Web 框架,我們將立即轉向 90 年代的互聯網,當時<marquee>
是每個人最喜歡的標籤,Geocities 網站上的旋轉 GIF 既時髦又前衛,Alta Vista 是首選。用於網絡搜索,命中計數器無處不在。
使用 Web 框架,您的第一行代碼似乎可以節省很多時間,但在某些時候,收益會變成損失。 你花時間閱讀如何讓框架做它不適合做的事情,如何集成庫並讓它們與框架配合得很好,並發現你在遵循框架標準的情況下構建的代碼是行不通的完全可以工作,現在你需要重寫它。 當你在沒有框架的情況下做事時,你開始的速度會慢一些,但你會穩步前進。 最後,這一切都是關於你想要簡單的部分。 總時間不會有太大區別。
我的代碼會比長城還長。 沒有框架的寫作就像買電影而不是訂閱流媒體服務。 您無法即時訪問數百部您想觀看的電影,但您也不必花錢購買數千部您甚至從未考慮從商店下載的電影。 你可以只寫你需要的。
中間人有用嗎? 當然。 但這通常不是必需的。 您編寫的每一行代碼都具有更多意義,因為您無需適應框架的要求。 感覺就像你在用純 JavaScript 編寫更多代碼,因為創建 DOM 元素的方式需要幾行代碼來創建一個元素,將它附加到 DOM,並且可能添加一個樣式類,而不是調用一行JSX 中的代碼。 但是,如果您使用 jQuery 或 React 之類的庫比較代碼,vanilla JS 的長度可能非常相似。 有時它更長,但有時它也更短。
沒有必要重新發明輪子。 計算機科學教授的口頭禪無處不在。 這是真的——它只是不必專門指框架。 例如,發送 Ajax 請求以加載或保存數據是幾乎每個 Web 應用程序的要求,但沒有框架並不意味著您每次都需要重新編寫代碼。 您可以創建自己的庫或代碼庫,也可以從其他人那裡提取代碼。 它越小,就越容易根據需要進行修改或調整,因此當您需要某個項目的特定內容時,它會派上用場。 修改 100-200 行代碼比瀏覽第三方庫或框架可能包含的大量文件更容易。
它只適用於小型項目。 這是一個非常普遍的神話,但根本不是真的。 目前,我正在開發一個完整的系統,以便在一個地方在線管理公司的所有方面,包括一個類似於 Google Drive 的模塊。 無論是否使用框架,我都會經歷非常相似的步驟並遇到非常相似的問題。 差異可以忽略不計。 但是,如果沒有框架,我的整個代碼會更小且更易於管理。
我要證據
好的。 讓我們停止談論理論,跳到一個現實世界的例子。 幾天前,我需要展示帶有商店徽標的品牌列表。 最初的代碼使用 jQuery,但它有一個問題,當在 Mozilla 中加載時,它會為尚未上傳徽標的品牌顯示一個損壞的圖像圖標。 我們不能因為 X 公司還沒有完成他們的工作而讓商店看起來未完成,但該功能需要上線。
以下代碼使用.innerHTML
的 jQuery 等效項:
var list_brand_names = ['amazon', 'apple', 'nokia']; var img_out = ''; for (i=0;i<list_brand_names.length;i++) { var brandName = list_brand_names[i].toLowerCase(); img_out += "<a href='/pages/" + brandName + "'><img src='images/" + brandName + "' /></a>"; } jQuery("#brand-images").html(img_out);
沒有深入探討 jQuery 的優缺點,這裡的問題是我們沒有對我們創建的圖像的任何引用。 雖然有些解決方案不涉及更改代碼,但讓我們藉此機會看看如何在沒有任何庫的情況下完成它:
var brands = ['amazon', 'apple', 'nokia']; var brand_images = document.getElementById("brand-images"); for (var iBrand = 0; iBrand < brands.length; iBrand++) { var link = document.createElement('a'); link.setAttribute('href', '/pages/' + brands[iBrand]); link.style.display = 'none'; brand_images.appendChild(link); var image = new Image(); image.src = "images/" + brands[iBrand] + "png"; image.onload = function(){ this.parentNode.style.display = ''; } link.appendChild(image); }
原始的 jQuery 代碼長達六行,而 vanilla JS 解決方案則需要十二行。 為了解決這個問題,隱藏每個圖像直到它被加載,需要兩倍的時間來編碼。 所以讓我們看看替代方案。 它也可以在jQuery中解決嗎? 看看這個:
img_out += "<a href='/pages/" + brandName + "'><img src='images/" + brandName + "' onload="showImage(this)"/></a>"; function showImage(image){ image.parentNode.style.display = ""; }
加上幾行代碼,現在 jQuery 和 vanilla 之間只有三行區別,但是在 jQuery 上,您可以看到img_out
行很快變得非常複雜,到了需要暫停的地步仔細想想你在做什麼。 直接用節點函數來編碼DOM,添加屬性、函數等可能會比較冗長,但是每一行都有更清晰、更準確的含義,方便以後閱讀和維護。
讓我們看一下 React:
function BrandLink(props) { var url = "images/" + props.brand + ".png"; return (<a href="{props.brand}"><img src={url}/></a>); } class Brands extends React.Component { constructor() { super(); this.state = {brands: ['amazon', 'apple', 'nokia']}; } render() { const links = this.state.brands.map((step, move) => { return (<BrandLink brand={step} key={step}/>); }); return (<div className="brands">{links}</div>); } } ReactDOM.render(<Brands />, document.getElementById("root"));
這個版本顯然是次優的。 代碼並不比原版中的短,我們甚至還沒有達到解決問題和隱藏鏈接的地步,直到其中的圖像加載完畢。
對於每個示例,結果都會有所不同。 有時,jQuery 會更短。 有時,React 會贏。 有時香草 JS 可能比它們都短。 無論如何,這裡的目標不是證明一個在本質上優於另一個,而是證明在代碼長度方面使用 vanilla JS 和使用框架之間沒有顯著差異。
結論
就像任何現實生活中的問題一樣,沒有什麼是非黑即白的。 沒有 Web 開發框架的編碼可能是您的某些項目的最佳解決方案,而在其他項目中則是一場噩夢。 就像每個工具一樣,關鍵不僅在於學習如何使用它,還在於學習何時使用它,以及使用它的優點和缺點可能是什麼。 使用純 JavaScript 進行編碼就像使用任何框架一樣 — 掌握它需要時間才能讓您感到自在使用它。
但關鍵的區別,至少對我來說,是框架來來去去,即使一個框架流行了很長時間,它也可以從一個版本到另一個版本發生巨大的變化。 純 JavaScript 將是一個更長的選擇,直到它完全不再相關並且出現了一些其他語言。 即便如此,與將給定框架遷移到另一種語言相比,您可以直接從一種語言遷移到另一種語言的概念和策略也會更多。 就單個項目而言,時間和精力大致相當,知識折舊的減少以及您可以為下一個挑戰學習的經驗是需要考慮的非常重要的因素。