Zet @ SITCON 2017
2017.03.18
早期的年代,前端不工程
頁面互動複雜度低
美術人員如果會一點基礎的 HTML、CSS 的話,與程式設計師配合就幾乎已經足以開發前端
架構單純,沒有可維護性或可重用性等問題
近年的前端工程化需求
Web Application 的普及,伴隨而來使用者介面的複雜性提高,需要有組織的架構與工作流程
舊有的前端技術與標準難以應付日漸增強的工程化需要
HTML 5 提供了大量的新特性,其中最重要的一類是提供瀏覽器原生的 RIA(Rich Internet Application)能力,而不再需要 Flash 等外部 Plugin
影片播放
音訊播放
繪圖
遊戲
視訊
早期各家瀏覽器對於標準的制定流程沒有共識,導致各瀏覽器的 DOM 操作或是 AJAX 等 API 都非常不一致
jQuery 帶來了在當時相當先進的思維與功能
抽象化統一各家瀏覽器的 API 操作差異
使用 CSS Selector 來選擇 DOM
鏈結串式操作的習慣
...etc
首個取得巨大成功與高程度廣泛應用的 JS 函式庫
現今已有點不敷使用於大型且複雜的前端應用程式開發,但仍然擁有承先啟後的重要歷史地位,在簡單的場景中也依然可以使用
Flash 在那個 HTML 原生不支援 RIA 功能的年代,提供了重要的替代方案,使得 Web 能夠更快速的流行於世界
ECMAScript 是 JavaScript 的語言標準規格,後者是前者的實作品
Node.js 是 ECMAScript 在伺服器端的實作品語言
ECMAScript 6 是 2015 年時正式發表的新一代版本標準,加入了許多重要的新語法與功能,令 JavaScript 往成為企業級語言邁進一大步
後面還有 ES7(ES 2016)、ES8(ES 2017)在規劃與實作中,慣例將之統稱為 ES6+,代表新時代的 JavaScript 版本
(Building Tool)
各家瀏覽器的支援還不夠完美與普遍,目前仍有部分功能未被實作完成
某些使用者可能永遠也不會更新到支援 ES6+ 的瀏覽器
因此我們需要依賴工具將我們的 ES6+ 程式碼轉譯成 ES5 環境能運行的版本,讓我們能放心無虞的使用 ES6+ 語法或功能來開發
Babel 是目前最主流的 JavaScript Transpiler
可以單獨運行,也可以配合 Webpack 這種前端打包工具一起使用
早期原名 6 to 5,專門處理 ES6 to ES5 的程式碼轉換
後來 Babel 決定平台化,除了可以使用官方維護的 ES6+ 與 React JSX 轉換功能之外,也提供 API 讓大家自行開發其他的擴充轉換功能
Babel 現今已經成為 ECMAScript 標準的重要推動力量
命名衝突
全域命名空間下容易造成變數命名衝突,尤其是跟第三方套件衝突時更難解決
程式碼間的順序與依賴性維護困難
開發人員必須自行理解並解決不同 JS 檔案之間,以及與第三方套件的相互依賴關係
在大型專案中各種資源難以管理,長期積累的問題導致程式碼庫混亂不堪
JavaScript 這個語言本身長時間以來都沒有設計這樣子的模組機制功能
因此社群只好自行設計並推廣一些民間標準
AMD
CommonJS:Node.js 採用的模組規範
直到 ES6 裡才制訂了原生的模組機制規範與語法
融合了各家社群標準的優點,並更加先進易用
ES6 Module 標準本身已經定案,但瀏覽器對於如何支援與配套仍然未有定論,因此前端至今仍無法原生支援模組系統
可以使用 Webpack 來做打包處理,以達到前端環境中模擬模組機制的效果
npm 本身是 Node.js(後端)的套件管理系統
因為 Node.js 的逐漸崛起以及 npm 的普及,前端的 JS 或 CSS 套件也被放上了 npm,漸漸也成為了前端的套件管理系統主流,通吃前後端
Bower 等純前端套件的管理系統逐漸式微
配合 Webpack 的模組機制模擬能力,可以讓一些本來只能在 Node 上使用的套件也能在前端中使用
在 JavaScript 中做非同步流程處理,傳統的方法是使用 Callback Function
當連續性的非同步 Callback 一多的時候,就像是...
const timeout = (delay) => new Promise((resolve, reject) => {
if (typeof delay == 'number') {
setTimeout(() => {
resolve(`${delay}ms passed away.`)
}, delay);
} else {
reject('input is a non-number value.');
}
});
timeout(3000)
.then(value => {
console.log(value);
}).catch(error => {
console.error(error);
});
// "3000ms passed away."
timeout('abc')
.then(value => {
console.log(value);
}).catch(error => {
console.error(error);
});
// "input is a non-number value."
const getArticleList = () => new Promise((resolve, reject) => {
$.ajax({
url: '/api/article/list',
dataType: 'json',
success: (result) => resolve(result)
});
});
const getArticle = (id) => new Promise((resolve, reject) => {
$.ajax({
url: `/api/article/detail/${id}`,
dataType: 'json',
success: (result) => resolve(result)
});
});
const getAuthor = (id) => new Promise((resolve, reject) => {
$.ajax({
url: `/api/author/${id}`,
dataType: 'json',
success: (result) => resolve(result)
});
});
getArticleList()
.then(articles => getArticle(articles[0].id))
.then(article => getAuthor(article.authorId))
.then(author => console.log(author))
.catch(error => console.error(error));
const getAuthorByArticle = async() => {
try {
const articles = await getArticleList();
const article = await getArticle(articles[0].id);
const author = await getAuthor(article.authorId);
console.log(author);
} catch (error) {
console.error(error);
}
}
Fetch 是目標取代 XHR 的新 AJAX 技術標準,已經被一些主流瀏覽器實作
是一個 HTML BOM 的 API,並非來自 ECMAScript 標準
Fetch 原生基於 Promise 實現,因此也可以直接搭配 async / await 使用
const getArticleList = async() => {
const response = await fetch('/api/article/list');
return await response.json();
}
const getArticle = async(id) => {
const response = await fetch(`/api/article/detail/${id}`);
return await response.json();
}
const getAuthor = async(id) => {
const response = await fetch(`/api/author/${id}`);
return await response.json();
}
try {
const articles = await getArticleList();
const article = await getArticle(articles[0].id);
const author = await getAuthor(article.authorId);
console.log(author);
} catch (error) {
console.error(error);
}
組件化開發
Virtual DOM
Ony-way Dataflow vs Two-way Binding
將 HTML 程式碼分拆為一個一個的組件模板
方便進行抽象化以及重用
React、Vue、Angular 2 等技術都有實現自己的組件機制,而 HTML 標準本身也在發展原生的組件系統
class ProductItem extends React.Component {
handleButtonClick = () => {
alert(this.props.price);
}
render() {
return (
<div className="item">
<div className="title">{this.props.title}</div>
<div className="price">{this.props.price}</div>
<button onClick={this.handleButtonClick}>購買</button>
</div>
);
}
}
在框架與瀏覽器 DOM 之間實作一套模擬的 DOM 夾層
當畫面需要改變時
根據最新的資料重繪出新的 VDOM Tree
與改變前的舊 VDOM Tree 進行全面式的比較與計算
其中新舊差異的地方,才真的會在實際的 DOM 上發生操作改變,藉此來減少不必要的實體 DOM 操作以節省效能
One-way Dataflow
資料是 UI 發生改變的唯一變因,只有資料改變時才會導致 UI 改變,並且 UI 不能直接改變資料
Two-way Binding
UI 擁有直接改變特定資料的能力,自動與指定的資料做雙向綁定
React | Vue | Angular 2 | |
---|---|---|---|
類型 | 專注 UI | 專注 UI | 全能型框架 |
主導者 | 個人項目 | ||
組件化 | 是 | 是 | 是 |
Virtual DOM | 有 | v2 開始有 | 無 |
Dataflow | 單向 | 單向 / 雙向 | 單向 / 雙向 |
View 結構定義 | JSX | template / JSX | template |
學習門檻 | 中 | 低 | 高 |
新版的 HTTP 傳輸協定
能夠支援更好的平行加載資源
現今將多個資源打包成少數檔案的優化處理,未來可能不再是最佳實踐
主流的瀏覽器都已經支援
Google 推廣的一種 Web Mobile App 技術,目的是希望提高手機版網頁應用的體驗
安裝性:可以瞬間添加到主畫面並且全螢幕運行,不用包成真的的 App 到 Store 裡下載安裝
離線使用:安裝時會將應用的基本架構暫存在本地端,以達到在斷網或網路訊號弱的時候依然能秒開的體驗
推播:能夠主動發起推播訊息
使用 JavaScript 來開發原生的行動裝置 App(Android、iOS)
原理是框架包含了 JS 與原生程式的橋樑,以及 JS 程式碼翻譯引擎,以達到寫 JS 程式碼產原生組件的效果,並且兩大平台的應用能共用大部分程式碼
與 Web 三大前端應用方案有密切關係
React:React Native
Vue:Weex
Angular 2:NativeScript
各大瀏覽器廠商合作發展的一項技術,目的是能夠將其他程式語言經過編譯之後在瀏覽器環境中執行
目前主要的用途導向是遊戲(C++)
還在初期階段,到正式廣泛應用可能還要 5 ~ 8 年的時間
發展順利並成熟的話,我們可能可以看到用多個語言皆可撰寫前端程式的一天
模組系統可能會在瀏覽器上原生實現
Babel 繼續擔任 ECMAScript 的重要推動力量
React 依然稱霸,核心重寫之後的新版會再一次掀起前端方案的效能與思想之爭
Vue 會迎來高峰,力壓 Angular 2 的地位,緊逼 React
Redux 依然在 State 管理的主流競爭者當中
HTTP / 2 普及
HTML 原生的 Web Component 依然受到冷落,但伺機而動
更多前端技術與開發廠商放棄支援 IE 8,IE 9 準備上刑場
前端工程由於使用者體驗的需求提高、UI 複雜度大幅增加而重要性提高
各種行動裝置、平台更讓前端的需求廣泛
HTML 5 的發展、Hybrid App、PWA、JS Bridge Native App 讓 Web 前端工程師能有效的跨足於行動裝置平台的開發
前端技術發展熱絡,工程化技術不斷在推翻與進步
對前端工程師來說,學習的能力非常重要
實體書籍
網路資源:文章、影片課程、線上社團、線上讀書會
社群活動:Conf、小型分享會、工作坊
實習、接案
認識並跟其他人交流、溝通、合作