[譯文] 現代 js 框架存在的根本緣由

原文連接:The deepest reason why modern JavaScript frameworks existjavascript

衆成翻譯地址:現代 js 框架存在的根本緣由(翻譯同樣是我翻譯的,但它缺了幾張圖,所以掘金從新發了~)css

精讀《現代 js 框架存在的根本緣由》 by 黃子毅(感謝大神的精讀,也是根據他的建議看了原文,也順便爲你們帶來翻譯)前端

我曾見過不少不少人盲目地使用(前端)框架,如 React,Angular 或 Vue等等。這些框架提供了許多有意思的東西,然而一般人們(自覺得)使用框架是由於:java

  • 它們支持組件化;
  • 它們有強大的社區支持;
  • 它們有不少(基於框架的)第三方庫來解決問題;
  • 它們有不少(很好的)第三方組件;
  • 它們有瀏覽器擴展工具來幫助調試;
  • 它們適合作單頁應用。

但這些都不是使用框架的根本緣由。git

最最本質的緣由是:github

(UI 與狀態同步很是困難)

是的,就是這緣由,讓咱們來看看爲何

假設你正在設計這樣一個 Web 應用:用戶能夠經過羣發電子郵件來邀請其餘人(參加某活動)。UX/UI 設計師設計以下:(在用戶填寫任何郵箱地址以前,)有一個空白狀態,併爲此添加一些幫助信息;(當用戶填寫郵箱以後,)展現郵箱的地址,每一個地址的右側均有一個按鈕用於刪除對應的地址。web

這個表單的狀態,能夠被設計爲一個數組,裏面包含若干對象,對象由郵箱地址和惟一標識組成。開始的時候,數組爲空。當(用戶)輸入郵箱地址並按下回車鍵以後,往數組中添加一項並更新 UI。當用戶點擊刪除按鈕時,刪除(數組中對應的)郵箱地址並更新 UI。你感受到了嗎?每當你改變狀態時,你都須要更新 UI數組

(你可能會說:)那又怎樣?好吧,讓咱們看看如何在不用框架的狀況下實現它:瀏覽器

用原生(JS)實現相對複雜的 UI

如下代碼很好地說明了使用原生 JavaScript 實現一個相對複雜的 UI 所需的工做量,使用像 jQuery 這樣經典的庫也須要差很少的工做量。服務器

在這個例子中,HTML 負責建立靜態頁面,JavaScript 經過 document.createElement 動態改變(DOM 結構)。這引來了第一個問題:構建 UI 相關的 JavaScript 代碼並不直觀易讀,咱們將 UI 構建分爲了兩部分(譯者注:應該是指 HTML與 JavaScript 兩部分)。儘管咱們使用了 innerHTML,可讀性是加強了,但下降了(頁面的)性能,同時可能存在 CSRF 漏洞。咱們也可使用模板引擎,但若是是大面積地修改 DOM,會面臨兩個問題:效率不高與須要從新綁定事件處理器。

但這也不是(不使用框架的)最大問題。最大的問題是每當狀態發生改變時都要(手動)更新 UI。每次狀態更新時,都須要不少代碼來改變 UI。當添加電子郵件地址時,只須要兩行代碼來更新狀態,但要十三行代碼更新 UI。(此例中)咱們已經讓 UI(界面與邏輯)儘量簡單了!!

代碼既難寫又難理解,更麻煩的是它很是脆弱。假設咱們須要(添加)同步服務器數據到郵件地址列表的功能,咱們須要對比服務器返回結果與數組中數據的差別。這涉及對比全部數據的標識與內容,(當用戶修改後,)可能須要在內存中保留一份標識相同但內容不一樣的數據。

爲了高效地改變 DOM,咱們須要編寫大量點對點(譯者注:指狀態到 UI)的代碼。但只要你犯下了很小的錯誤,UI 與狀態將再也不保持同步:(可能會出現)丟失或呈現錯誤的信息、再也不響應用戶的操做,更糟糕的是觸發了錯誤的動做(如點了刪除按鈕後刪除了非對應的一項)。

所以,保持 UI 與狀態同步,須要編寫大量乏味且很是脆弱的代碼。

響應式 UI 拯救一切

因此,(之因此使用框架,)不是由於社區,不是由於工具,不是由於生態,不是由於第三方庫......

目前爲止,框架最大的改進是(爲咱們)提供了應用內部狀態與 UI 同步的可靠保證。

只要你清楚特定框架的某些(特定)規則(如不可變狀態),就差很少(能夠正常使用)了。

咱們只須要定義一次 UI 界面,再也不須要爲每一個操做編寫特定的 UI 代碼,同時,每一個相同的狀態均有相同的輸出(譯者注:指 UI 一致):當狀態改變後,框架自動更新(對應的)視圖。

框架是如何工做的呢?

基於兩個基本的策略:

  • 從新渲染整個組件,如React。當組件中的狀態發生改變時,在內存中計算出(新的)DOM 結構後與已有的 DOM 結構進行對比。實際上,這是很是昂貴的。於是採起(將真實 DOM)映射爲虛擬 DOM ,經過對比狀態變化先後虛擬 DOM 的不一樣,計算出變化後再改變真實 DOM 結構。這個過程稱爲調和(reconciliation)。

  • 經過(添加)觀察者監測變化,如 Angular 和 Vue.js。應用中狀態的屬性會被監測,當它們發生變化時,只有依賴了(發生變化)屬性的 DOM 元素會被從新渲染。

那 Web components 呢?

不少時候,人們會把 React、 Angular 和 Vue.js (等框架)與 Web components 進行對比。這顯然體現了人們並不理解這些框架所提供的最大好處:保持 UI 與狀態同步。Web components 並不提供這種同步機制。它僅僅提供了一個<template>標籤,但它不提供任何(狀態與 UI 之間的)協調機制。若是你在應用中使用 Web components 時,想保持 UI 與內部狀態同步,則須要(開發者)手工完成,或者使用如 Stencil.js (內部和 React同樣,使用虛擬 DOM)之類的庫。

讓咱們明確一點:框架表現出的巨大潛力並不體如今組件化上,保持 UI 與狀態同步纔是具體的體現。Web components 並未提供相關的功能,你必須手工或使用第三方庫去解決(同步的)問題。使用原生 JavaScript 去編寫複雜、高效且易於維護的 UI 界面基本上是不可能的。這就是你須要使用現代 JavaScript 框架的根本緣由。

本身動手,豐衣足食

若是熱衷於瞭解底層原理,想知道虛擬 DOM 的具體實現。那,爲什麼不試着在不使用框架的狀況下,僅使用虛擬 DOM 來重寫原生 UI呢?

這裏是框架的核心,全部組件的基礎類。

這裏是重寫後的 AddressList 組件(藉助 babel 來支持 JSX 的轉換)。

如今 UI 是聲明式的,咱們並未使用任何框架。咱們能任意添加新邏輯來改變狀態的同時,不須要編寫額外的代碼來保持 UI 同步。問題解決了!

如今,除了事件處理以外,這看起來就像個 React 應用對吧?咱們有haverender()componentDidMount()setState()等等。一旦解決了保持應用內 UI 與狀態的同步問題,全部東西就會很天然地疊加起來(造成組件)。

能夠在這個 Github 倉庫中找到完整的源代碼。

結論

  • 現代 js 框架解決的主要問題是保持 UI 與狀態同步。
  • 使用原生 JavaScript 編寫複雜、高效而又易於維護的 UI 界面幾乎是不可能的。
  • Web components 並未提供解決同步問題的方案。
  • 使用現有的虛擬 DOM 庫去搭建本身的框架並不困難。但並不建議這麼作!
相關文章
相關標籤/搜索