全鏈路前端性能優化
通常來講前端性能優化是指從用戶開始訪問我們的網站到整個頁面完整的展現出來的過程中,通過各種優化策略和優化方法讓頁面加載的更快,讓用戶的操作響應更及時,給用戶更好的使用體驗。
這里我們介紹的是前端性能優化知識的解決方案,從靜態資源優化開始入手,從表象深入體系化的講解頁面渲染架構,掌握搞笑的技術方案。
本文並非細節的講述如何實現性能優化,而是從各個方面介紹性能優化的方式方法,並且不僅限於H5,因為當今的前端也不僅僅只有H5。
圖片資源優化
- 圖片格式介紹
jpeg: 一種針對彩色照片而廣泛使用的有損壓縮圖形格式。是一種柵格圖形,常用文件擴展名為jpg,jpeg,jpe。在互聯網上常被應用於存儲和傳輸照片。不適合線條圖形和文字,圖標圖形,因為他的壓縮算法不支持這些類型的圖形,並且不支持透明度。常用於色彩豐富的照片,彩色圖大焦點圖banner等結構不規則的圖形。
png: 便攜式網絡圖形,是一種無損壓縮的位圖圖形格式,支持索引、灰度、RGB三種顏色,以及Alpha通道等特性。他最初的設計是為了代替GIF,能夠支持半透明和透明特性,最高支持24位彩色圖形和8位灰度圖像。不過由於是無損壓縮所以文件體積太大。比較適合純色,透明,線條繪圖,圖標以及顏色較少的需要半透明的圖片。
GIF: 位圖圖形文件格式,8位色重現真彩色的圖像,采用LZW壓縮算法進行編碼。支持256色,僅支持完全透明和完全不透明,可以支持動圖,不過每個像素只有8比特,不適合存儲彩色圖片。常用與動畫和圖標。
webp: 是一種現代圖像格式,可以提供無損壓縮和有損壓縮兩種。可以同時辦證一定程序上的圖像質量和較小的體積,可以插入多幀,實現動畫效果。支持透明度。采用8位壓縮算法,無損的webp比png小26%,有損的webp比jpeg小25-34%,比gif有更好的動畫。不過最多可以處理256色,不適合彩色圖片。常用於圖形和半透明圖像。
- 圖片優化
對於png圖片來說,可以使用jdf-png-native進行壓縮, 他是node-pngquant-native工具的封裝包,這個工具跨平台,壓縮比高,而且壓縮png24也非常的好。
const pngquant = require('jdf-png-native'); const fs = require('fs'); fs.readFile('./in.png', (err, buffer) => { if (err) { throw err; } const resBuffer = pngquant.option({}).compress(buffer); fs.writeFile('./out.png', resBuffer), { flags: 'wb' }, () => {}) })
壓縮jpg可以使用jpegtran這個工具,他也是一個node工具。使用方法比較簡單,直接使用命令即可。大概壓縮10%的占比。
jpegtran -copy node -optimize-outfile out.jpg in.jpg
對於gif文件來說可以使用gifsicle工具,他是通過改變每幀比例,減小gif文件大小,同時可以使用透明來達到更小的文件體積。是一個公認的解決方案。可以去http://www.lcdf.org/gifsicle/
中去安裝。使用方式同樣也是命令行方式。
gifsicle --optimize=3 --crop-transparency -o out.gif in.gif
這里的優化級別不要小於2,1的話代表不壓縮。壓縮后基本不失幀。
還有一種壓縮方式是圖片可以根據網絡環境來展示不同尺寸和像素的圖片,通過在url后綴加不同參數來實現。比如下面的地址, 430可以修改為800來獲得不同體積的圖片。
https://img.alicdn.com/imgextra/i1/2616970884/O1CN01x6HnoK1IOuj5IosXO_!!2616970884.jpg_430x430q90.jpg
- 響應式圖片
響應式圖片是我們可以在用戶不同的窗口大小還有設備像素的情況下來展示不同大小的圖片,可以用以下三種方式來實現, 第一種是可以使用js來綁定事件檢測窗口大小,以此來設置圖片的大小。第二種方式就是css的媒體查詢。
@media screen and (max-width: 640) { my_image { width: 640px; } }
第三種可以使用html5的srcset來設置,他會根據設備的像素比來自動選擇需要的圖片。而且不支持srcset的瀏覽器也可以正常展示src的屬性。
<img srcset="img-320w.jpg, img-640w.jpg 2x, img-960w.jpg 3x" src="img-960w.jpg" alt="img" />
- 逐步加載圖片的方式
其實就是延遲加載,在真實的圖片加載出來之前,可以使用一張公共的圖片,一般是公司的logo,先將布局撐起來,然后再換成真實的圖片。
lqip這個工具可以將真實的圖片虛化,轉換為很小的base64編碼。這樣我們可以先使用base64加載虛化的圖片。
npm install lqip
const lqip = require('lqip'); const file = './in.png'; // image lqip,base64(file).then(res => { console.log(res); // 輸出base64 }) // color lqip.paletter(file).then(res => { console.log(res); // 圖片顏色值 })
也可以使用低質量圖片占位符, 他是基於SVG的圖像占位符實現的。
npm install sqip
const sqip = require('sqip'); const result = sqip({ filename: './in.png', numberOfPrimitives: 10 // 效果值 }); console.log(result.final_svg); // 輸出svg格式
相比lqip來說sqip效果會好很多,而且可以設置不同的大小。
- 其他方式
可以使用web font來代替圖片,比如說小圖標等業務小圖片。
也可以用dataurl的方式,也就是前面的base64的方式來代替圖片,這樣用戶就不需要發送http請求了。
也可以采用雪碧圖將多個小圖片合成一個大圖,這樣也會節省很多的圖片請求。
- 圖片服務器自動優化
圖片服務器優化是指可以在圖片url連接上增加不同特殊參數,讓服務器自動生成不同格式,大小,質量的圖片。
比如說可以對圖片做一些裁剪,裁剪成我們需要的圖片,也可以支持不同格式的轉換,比如說jpg,gif,png,webp等也可以設置圖片的壓縮比。
也可以對圖片添加一些水印,高斯模糊,重心處理等還可以增加一些AI的能力,比如說用戶上傳的圖片是否涉黃。還可以通過智能摳圖,智能排版,智能配色智能合成等功能完善圖片。
HTML的優化方法
- 精簡html代碼
可以減少html的嵌套也就是層級關系盡量減小,也可以減小DOM節點數也就是盡量壓縮優化DOM的節點數, 讓瀏覽器渲染的DOM節點數最少。
減少一些無語義的代碼,比如說空標簽清浮動那種代碼<div class="clear"></div>
能不用最好不要用。
建議連接中刪除http或者https,因為一般鏈接的協議頭和頁面的協議頭都是一致的,寫他們多了4-5個字符其實是沒有什么意義的。而且可以減少代碼體積。
也可以刪除多余的空格,換行符,縮進和不必要的注釋,一般會用壓縮工具來處理這個過程。可以省略一些標簽和屬性。使用相對路徑的url,最大范圍的減少字節數。
- 文件位置
css文件鏈接盡量放在頁面頭部,css加載不會阻塞DOM Tree解析,但是會阻塞DOM Tree渲染,也會阻塞后面js執行。也就是說DOM Tree在渲染前就要解析好CSS,從而減少瀏覽器重排文檔的次數。而且css放在頁面底部會導致頁面白屏時間變長。
js文件一般放在頁面底部,這是防止js的加載和解析阻塞頁面元素的正常渲染。
- 用戶體驗
設置favicon.ico, 如果不設置控制台會報錯,而且用戶訪問的時候地址欄也是空的,不利於品牌記憶。
增加首屏必要的css和js,一般頁面需要在等待所有的依賴加載完成才會展示,這樣就會導致頁面存在空白。永祥用戶體驗,可以增加背景圖或者loading或者骨架屏,比空白頁好很多。
CSS優化細則
- 提升css渲染性能
謹慎使用一些expensive的屬性,比如nth-child偽類或者position:fixed定位,因為這些比較消耗瀏覽器的渲染性能。
盡量減少一些樣式層級的級數,比如,div ul li span i { color: red}, 其實我們可以給i標簽設置class,直接書寫樣式。
避免使用占用過多cpu和內存的屬性,比如text-indent不要設置太大的值。
盡量避免使用耗電量大的屬性,比較占用GPU, 比如transfrom是,transitions, opacity.
合適的使用css選擇器, 盡量避免使用通配符,避免使用css表達式。color: expression((new Date()).getHours() % 2 ? "#fff" : "#000")。
避免類正則的屬性選擇器。 *=, |=, ^=, $=,使用外鏈的css,可以單獨形成文件放在cdn,使用緩存形式加載。避免使用@import因為他的加載會阻塞進程,需要加載完畢才會向下執行。
精簡css代碼,使用縮寫的語句,比如margin-top可以寫在margin中,再者如果值為0能刪除就刪除,刪除不必要的單位值,刪除過多的分號,刪除空格和注釋。盡量減小樣式表的體積。其實這些都可以使用壓縮工具來處理,會方便很多。
- 合理使用web fonts
可以將字體文件部署到cdn上,加快用戶端的加載速度,也可以將字體以base64的形式保存在css中,並通過localStorage進行緩存。一些谷歌字體庫應該使用國內托管服務不要直接使用源地址。
- css動畫優化
避免同時動畫,也就是說用戶訪問的屏幕區間里面不要有過多的動畫,動畫太多會干擾用戶正常瀏覽網站,而且動畫多也影響瀏覽器的性能。
延遲動畫的初始化,可以讓其它css先渲染,讓動畫延遲,比如說0.5或1。
可以借助svg去展示動畫,樣式放在css里面控制。
JavaScript優化
首先我們是當需要的時候才去優化,不是為了優化而優化,一般的優化是在某一個時間點進行的,而且優化也需要考慮可維護性這是要結合團隊的研發水平和代碼的規范。
- 提升js文件的加載性能
這個基本每個人都知道,就是css文件放在head標簽中,js文件放在body結尾的地方。這個是js的加載不要影響html的渲染。
- 變量和函數方面的優化
盡量使用id選擇器,因為id選擇器在查詢效果上效率最快。
避免使用eval,這個方法比較消耗能行。
js函數盡可能保持簡潔,不要把太多內容寫在一個函數中。也建議使用事件的節流函數。事件委托等等。
- js動畫
盡量避免添加大量的js動畫,css3動畫和canvas動畫都比js動畫性能好。
使用requestAnimationFrame來代替setTimeout和setInterval,因為requestAnimationFrame可以在正確的時間進行渲染,setTimout和setInterval無法保證渲染時機。不要在定時器里面綁定事件。
- 使用邏輯緩存
緩存dom對象,也就是用一個變量來存儲dom對象,不要每次使用都查詢。
緩存列表長度,也就是說用變量存儲dom元素的個數,而不是每次都重新計算。
比如百度M站,會把頁面的css和js放在本地存儲里面,這樣后面再加載的時候就直接從本地存儲里面取,實現秒考的效果。不過本地存儲空間有限,要謹慎使用。
減少頁面回流和重繪
- css
避免過多的樣式嵌套,最好可以快速的定位到元素。
避免使用css表達式,css表達式會在css繪制的過程中都會執行,會增加重排和回流的次數。
可以使用絕對定位讓動畫元素脫離文檔流。
避免使用table布局他會引起瀏覽器的多次重繪,也不要使用float布局。
圖片最好設置好設置width和height,這樣圖片在加載之后布局就可以確定了。
簡化瀏覽器不必要額任務,使用viewport設置屏幕縮放級別。
避免頻繁設置樣式,將多個樣式操作合並修改,一次性的更新。
- js
為了減少回流發生次數,應該避免頻繁操作DOM,可以合並多次對DOM的修改,一次性批量處理。
控制繪制過程和繪制區域,繪制過程開銷比較大的屬性設置應當避免使用。
簡化DOM操作
眾所周知,頁面交互卡頓和流暢度很大一部分原因就是頁面有大量DOM元素,想想一下,從一個上萬節點的DOM樹上,使用querySelectorAll或getElementByTagName方法查找某一個節點,是非常耗時的,另外元素綁定事件時,事件冒泡和事件捕獲的執行也會相對耗時。所以一般我們應該合理的不熟業務邏輯,DOM節點過多時應該延遲即將呈現的DOM內容。
對DOM的操作最好統一處理后再統一插入到DOM Tree中。可以使用fragment對DOM和樣式設置好再統一放到頁面中去。
目前比較流行的框架,比如Angular,React和Vue都是使用虛擬DOM技術,通過diff算法簡化和減少DOM操作。
靜態文件壓縮工具
html-minifier: 壓縮html clean-css: css的壓縮工具 uglify-js: js文件的壓縮工具
瀏覽器渲染過程
首先瀏覽器會解析HTML生成DOM Tree,然后解析CSS生成CSSOM Tree。接着JS會通過DOM Api和 CSSOM Api來操作DOM Tree和CSS Rule Tree 將DOM Tree 和 CSSOM Tree合成一顆渲染樹Render Tree。
根據生成的渲染樹進行回流,以計算每個節點的幾何信息,包括位置,大小,樣式等等。然后根據渲染樹和回流得到的幾何信息,得到每個節點上的絕對像素。
最后將像素發送給圖片處理器也就是GPU進行頁面展示。
前端頁面渲染可以分為服務端渲染和客戶端渲染。服務端渲染有傳統的后端同步渲染,同構直出比如php,java, .net或者大家熟悉的node。
客戶端渲染也就是js渲染,前后端分離,單頁面應用。react, vue, ios,安卓,hybird app,flutter等。
懶加載,預加載,預渲染
懶加載也叫延遲加載,指的是長網頁中延遲加載特定元素,可以是圖片也可以是js和css。懶加載的好處是可以減少當前屏無效資源的加載。
一般我們會把img標簽的src屬性設置為空字符串,真實的圖片地址放在data-lazy中,當頁面scroll到對應的位置時再通過DOM操作將src的值替換為data-lazy的值。
預加載是讓瀏覽器預先加載某些資源,同樣也是圖片,js或者css,這些資源是在將來才會被使用的。
簡單來說就是講所需要的資源提前加載到瀏覽器本地,后面在需要的時候可以直接從瀏覽器的緩存中獲取,而不用再重新開始加載。好處是減少用戶后續加載資源等待的時間。
可以使用new Image的方式也可以使用標簽的方式preload,prefetch, preconnect
<link rel="preload" href="src/style.css" /> <link rel="prefetc" href="src/image.png" /> <link rel="dns-prefetch" href="https://my.com" /> <!-- 提前將dns緩存--> <link rel="preconnect" href="https://my.com" /> <!-- 提前加載需要的資源 -->
另一種預加載組件的方式就是提前渲染它,在頁面中渲染組件,但是並不在頁面中展示,也就是渲染好后先隱藏起來,用的時候再直接展示。可以使用prerender將https://my.com頁面先提前渲染好。
<link rel="prerender" href="https://my.com" />
接口服務調用優化
1.接口合並,指一個頁面的眾多的業務接口和依賴的第三方接口統一使用一個部署在集群的接口統一調用,以減少頁面接口請求數。
2.接口上CDN,主要基於接口性能考慮,我們可以把不需要實時更新的接口同步至CDN,接口內容變更自動同步CDN。
3.接口域名上CDN可以增強可用性和穩定性。
4.接口降級,這個基於大促備戰考慮,核心進行降級用基礎接口進行業務實現,比如千人千面的推薦接口,在大促時間點可以直接運營編輯的數據,另外接口萬一無法訪問,使用預設好的墊底備份數據。
5.接口監控,監控接口的成功率不是常說的服務器TP99,而是和用戶實際情況一直的成功和失敗監控,比如弱網,超時,網絡異常,網絡切換等情況。排查出來問題需要聯合后端,運維,網絡崗位人員一並解決。
接口緩存優化
1.ajax/fetch緩存,前端請求的時候帶上cache,依賴瀏覽器本身的機制來請求接口,這個比較適用於不會經常變更的數據。
2.本地緩存,異步接口數據優先使用本地localStorage中緩存的數據。可以讓服務端返回數據的時候再給一個md5值,然后將md5值和數據綁定存在本地,再次請求的時候對比這個md5值,如果相同就不要再請求獲取數據的接口了,如果不同就請求更新。
webview
原生的webview對於IOS來說有兩種,一種是UIWebView,他從IOS2開始就作為App內展示web內容的容易,而且排版布局能力比較強。
不過UIWebView也有很多的問題,比如說內存泄漏,運行期間會有極高的內存峰值,Touch Delay延遲300毫秒。js運行性能不高,在2018年的ios12以后就不再維護了。
WKWebView是蘋果在WWDC 2014上推出的新一代WebView組件,WKWebView的內存開銷比UIWebView要小很多,而且在性能,穩定性,內存占用方面都有很大提升。可以實現60fps的滾動刷新率,自身就支持了右滑返回手勢,支持更多的HTML屬性。內存占用是UIWebView的1/4 ~ 1/3, 加載速度比UIWebView提升了一倍左右。大幅度提升了js執行速度。允許js的Nitro庫的使用,UIWebView是不允許的。可以和js直接互調函數,不需要使用jsbridge來協助。
當然WKWebView不支持頁面緩存,需要自己注入cookie,而UIWebView是自動注入cookie的。他也無法發送POST參數。
對於安卓來說存在webkit for webview 和 chromium for webview。
webkit是一個開源項目,前身是khtml和kjs,專注於網頁內容的展示,做了一流的頁面渲染引擎,他不是瀏覽器而且也不想成為瀏覽器,這個項目包含兩個部分,第一個部分是WebCore, 其中包括對html,css很多w3c規范的實現,第二部分就是狹義上的webkit主要是各個平台的移植並提供相應的接口。也就是webview和類似於webview,這樣的接口提供操作和顯示網頁的能力。
目前使用WK的主流瀏覽器或者webview包括chrome,safari, 安卓平台以及眾多的移動瀏覽器。
chromium是基於webkit之上的一個瀏覽器項目,由谷歌來發起,這個項目發展的還是比較迅速的,他對新特性的支持還是比較好的,比如webgl,css3,h5等等,在性能方向也非常不錯chrome一般選擇穩定的chromium作為基礎。
Webkit for Webview | Chromium from Webview | 備注 | |
---|---|---|---|
版本 | Android4.4以下 | Android4.4以上 | -- |
JS解釋器 | WebCore JavaScript | V8 | -- |
H5 | 278 | 434 | -- |
遠程調試 | 不支持 | 支持 | Android4.4及以上支持 |
內存占用 | 小 | 大 | 相差20-30M |
WebAudio | 不支持 | 支持 | Android 5.0及以上支持 |
WebGL | 不支持 | 支持 | Android 5.0及以上支持 |
WebRTC | 不支持 | 支持 | Android 5.0及以上支持 |
安卓第三方內核,主要是安卓的版本較多,對WebView二次封裝產生的,這里主要說下X5內核。
他的速度是比較快的相比系統WebView的網頁打開速度有30%的提升,在流量方面使用雲端優化技術節省20%以上。安全問題可在24小時內修復。更穩定經過億級用戶的使用考研,CRASHE(崩潰)率低於0.15%。沒有系統內核的碎片化問題,更小的兼容性問題,支持夜間模式,適屏排版,字體設置等瀏覽器增強功能。在H5和ES6上有更完整的支持,集成了強大的視頻播放器,支持視頻格式遠多於系統的WebView,視頻和文件的格式支持X5內核多於系統內核,自帶防劫持。
一般webview選型,IOS建議使用WKWebView, 安卓建議使用X5。
WebView性能優化
當App首次打開時,默認是不初始化瀏覽器內核的,當創建WebView實例的時候,才會啟動瀏覽器內核,打開事件需要70-700毫秒,並創建webview的基礎框架。
可以使用全局的Webview對延遲的毫秒進行優化,就是在客戶端啟動的時候,就初始化一個全局的WebView待用,當用戶訪問Webview的時候直接使用這個WebView加載對應網頁。
這樣會減少首次打開WebView的時間,缺點是會有一些額外的內存消耗。
導航欄可以預加載,以前是在webview加載完成之后進行初始化,可以改為和webview並行一起加載。
對於登錄來說H5頁面上接口每次查詢Cookie中是否有登錄態,無登錄態H5跳轉統一登錄頁,App登錄成功寫入Cookie。可以改為Cookie統一在Webview中設置cookie。也就是初始化Webview的時候判斷是否登錄,如果登錄了就打開H5頁面,如果沒登錄就自動跳轉登錄頁面。
webview加載頁面的url盡量前置,不要放在最后,可以和業務邏輯並行處理,總而言之減少頁面的白屏時間,讓用戶最快的看到頁面。
提升滾動條的使用體驗,原本是使用系統自帶的滾動條的進度值,可以自己模擬滾動條的加載過程,讓用戶感覺頁面加載變快了。也就是初始快速的加載到60%以上,給用戶感覺加載很快的感覺。其實真實速度並沒有變...
js-sdk優化,也就是oc和js通信的一個方式。一般jssdk有三種方式實現,第一種就是常見的scheme的方式,就是我們在h5頁面里面定義一些特殊的鏈接,拿到這個scheme之后原生攔截。然后把需要的回調函數和參數進行攔截,但這樣有個問題,url一般是256個字符,有長度的限制不能無限的傳遞。
第二種是iframe的形式,通過后台啟一個頁面進行攔截取iframe的變更拿到js的方法給oc實現通信,iframe是依賴jssdk.js文件的,需要sdk文件作為橋梁實現通信目的。
第三種是webkit的方式,他是一種直接調用的方式,無需依賴任何的sdk文件。
瀏覽器緩存策略
緩存機制 | 優勢 | 適用場景 | Android 開關 | IOS開關 |
---|---|---|---|---|
瀏覽器緩存機制 | HTTP協議層支持 | 靜態文件的緩存 | 瀏覽器負責 | 瀏覽器負責 |
Web Storage | 較大的存儲空間,使用簡單 | 臨時,簡單數據的緩存,瀏覽器上的LocalStorage、SessionStorage | webSettings.setDomStorageEnabled(true) | 默認開啟無關閉 |
Web SQL Database | 存儲,管理復雜結構數據 | 建議用IndexDB 替代 | webSettings.setDatabaseEnabled(true) | 默認開啟無關閉 |
Application Cache | 方便構建離線App | 離線App,靜態文件緩存 | webSettings.setAppCacheEnabled(true) | 默認開啟無關閉 |
IndexDB | 存儲任何類型數據,使用簡單,支持索引 | 結構,關系復雜的數據存儲 | webSettings.setJavaScriptEnabled(true) | 默認開啟無關閉 |
H5離線化的實現方式
全局離線包,包含公共的資源,可供多個應用共同使用。
還可以有私有化的離線包,只可以被某個應用單獨使用。
離線包的工作原理:
首先會加載一個全局的包就是一些基礎的文件,加載之后會把包釋放放在內存里,接着會做一個檢測,查看本地是否安裝,如果已經安裝就釋放到內存,如果沒有安裝就觸發離線包的下載,就是我們做好的包放在服務器中,然后從服務器獲取過來,在下載之前會進行一個本地和線上版本的對比,版本不一致的話就會下載最新的包,如果一致就取本地的就可以了。
最終這個包會解壓釋放在內存里面,當webview在加載url的時候會直接從內存里面讀取,如果能讀取到就加載內存中的頁面數據進行展示,假設讀取不到也就是說本地沒有這個業務就會使用線上的url地址讓頁面加載就可以了。因為我們一般不會把所有的業務都做成離線化的形式,假設webview查詢的到就用離線化,查詢不到就用墊底的線上url展示。無論本地離線包加載失敗還是沒有這個離線包,都使用線上url來墊底。
離線包的下載一包情況下如果用戶處於移動網絡狀態下,不會在后台下載離線包,如果當前用戶點擊app,離線包沒有下載好,用戶就要等待離線包下載好才能用。可以采取wifi靜默下載的方案。
從服務器請求的離線包信息存儲到本地數據庫的過程中,離線包信息包括離線包的下載地址,離線包版本號,加密簽名信息等,安裝離線包其實就是將離線包從下載目錄拷貝到手機安裝目錄。
一些大廠的離線包方案比如美團的LsLoader通用移動端WebApp離線化方案,騰訊的Alloykit手Q離線包,阿里的極致Hybrid航旅離線包再加速。原理基本上都是一致的,細節上可以做些參考。
混合開發介紹
1.RN React Native是基於React語法的, 希望實現的是一套代碼可以在各個端使用。他的優勢很明顯,代碼是可以共享的無論是IOS還是安卓還是H5,性能方面幾乎也與Native相同。並且提供了非常流暢的動畫,因為他在渲染之前代碼就已經轉換為了原生視圖。
調試時無需每次代碼變更都編譯打包,可即時查看更小效果,極大提高了開發人力。
支持熱更新,不需要每次發版都發布應用到商店,發版時間可以自由控制,安卓和ios同時發版。
一共分成四層實現,最下面是native的原生層也就是OC和Java,在這之上是UI渲染器,圖片處理,網絡通信,和一些工具庫,再向上是C++: JSCore,Bridge也就是js的運行環境和js和native的橋接。最上面才是js層也就是js的一些組件。
RN的jsx文件通過JSBridge會針對不同平台打包成不同的格式,比如IOS的.m文件,安卓的.xml文件,以及H5的.html文件。
為什么會有RN其實是因為應用商店發版的問題,每一次發版都需要審核,可能審核不通過,而且安卓可能要發布多個商店,還有兩端研發不同步的問題,也就是安卓和ios相同的業務需要開發兩遍。
如果你公司的技術是React全家桶,那還是建議選用RN的。
小程序
小程序的願景是觸手可及,用戶掃一掃或者搜索下就可以打開應用,不需要安裝太多應用。
向程序相比App,開發門檻更低,優於H5接近Native的體驗,可以使用相機,位置,網絡,存儲等豐富的原生能力。支持頂部下拉,搜索,掃碼等入口,簡單方便,用完即走,不需要像App那樣下載,直接打開支持熱更新。
小程序出現的行業背景,對於App大廠來說需要流量變現,比如微信,他是沒辦法變現的,所以可以使用小程序生態將第三方引入進來,形成了一個小型的應用市場。對於企業應用來說,移動流量枯竭,獲客比較困難,可以降低獲客成本和開發成本,業務上提供更多的試錯機會。
平台類產品如果輸出給商家端,相比多個app的方式,比較推薦使用小程序。
Flutter
號稱編寫一次可以部署到各個終端,web, android,ios,mac,linux,windows,fuchsia os。
底層使用Skia圖形引擎,圖形性能媲美原生應用,界面更像一個全屏應用程序或2D游戲,速度比較快,使用本機ARM二進制文件,做到提前編譯,不需要JVM,也就是java虛擬機。
底層實現
flutter在2017年5月份出現,生態不夠豐富,學習曲線相對較高,但是他的性能較好,如果考慮性能,團隊人員足夠的話建議選擇fluttr。
CDN
CDN是內容分發網絡,利用每一台最靠近用戶的服務器,更快更可靠的將文件發送給用戶。以加快訪問速度。
CDN的有點很明顯,因為會給用戶指派較近,較順暢的服務器節點,所以速度會比較快,服務器放在不同地點,減少了互聯的流量,也降低了快帶成本,當某個服務器故障時,自動調用臨近地區的服務器。
回源是指瀏覽器訪問CDN上靜態文件時,文件緩存過期,直接穿透CDN而訪問源站機器的行為。這是CDN的一個策略。
CDN的緩存分為三級,瀏覽器本地緩存也就是header頭配置的緩存,CDN邊緣節點緩存,CDN源站緩,一般是三級,也可能業務比較少就采用兩級緩存,瀏覽器緩存和CDN源站緩存。
緩存時間設置過短的話,CDN邊緣節點緩存經常失效,導致頻繁回源,增大了源站負載,訪問速度也會變慢,緩存時間設置的過長,文件更新慢,用戶本地緩存不能及時更新,所以一般是結合業務情況而定。
一般不同資源類型緩存時間設置不用,html一般3分鍾左右,js,css可以10分鍾,一天,一個月,看變更情況。
現在一般我們文件的命名都會以hash串的形式,如果文件有變更生成的文件名就會有變更,否則還是之前的名字,這樣我們緩存的時間就可以設置的長一些。
CDN可以灰度發布,也就是在部分地區部分運營商優先發布靜態資源,驗證通過后再進行全量發布。具體實施可以從域名方面下手,設置特殊VIP解析到要灰度的城市或者運行商。也可以調整源站機器,給灰度的城市或者運營商配置單獨的源站機器。
一般在活動期間比如說大促,需要增加機房寬帶,增加運營商流量,增大CDN緩存時間等等。
DNS
DNS是將網站域名和地址互相映射的一個分布式數據庫,我們訪問一個網站首先會通過DNS將域名匹配為ip地址,然后再通過ip地址去訪問對應的服務器。
客戶端里面有一個http dns, 客戶端直接訪問http的接口,可以獲取業務在域名訪問系統中配置的最優ip,基於容災的考慮,app內是需要保留使用運營商DNS解析方式的,客戶端再獲取到ip后會直接向ip中發送業務請求。
比如一個http請求,在header中會指定host字段,向ip發送標准的http請求就可以了,總的來說采用http-dns來解析域名能繞過三四級運營商接續域名出現的一些問題,在http-dns返回的正確ip之后是直接使用ip去發送http請求的,只需要關注通信內容的安全就可以了。
安卓系統可以采用okhttp模塊,他支持http2,http2可以在一個鏈接上一次性發送多個請求,支持gzip,也支持響應緩存避免網絡重復請求,如果服務器配置了多個ip地址,當第一個ip鏈接失敗的時候,okhttp會自動嘗試下一個ip地址。
ios沒有現成的模塊,我們可以在app啟動時,緩存所有可能要用到的域名ip比如接口,網關,同時異步處理,客戶端無需得到緩存結果。如果cache中有此域名的圓環,直接返回緩存的ip,如果緩存中沒有此域名,則重新向httpdns server進行申請然后緩存下來。
H5的做法一般是設置多個域名,因為瀏覽器對並發數是有限制的,一個域名一般最大連接數是6,所以我們可以將用戶訪問的一些api接口作為一個域名,頁面中的樣式和資源可以設置成一個域名,圖片也可以單獨設置成一個域名,甚至多個域名,來打破瀏覽器的這種限制。
http優化
http的優化主要就是減少請求數,這可能是我們日常工作中經常遇到的,也是大家耳熟能詳的。
圖片可以使用雪碧圖,dataurl, webfont。
可以考慮將業務中的js或者css合並,不要切割的太小。如果不想合並成一個可以使用Combo的方式讓服務去返回,可以在url上通過參數的形式告訴服務加載那些資源。
接口也可以合並,不要拆分的太細,可以讓服務去合並,不經常變化的接口和資源也可以存儲在LocalSrorage,有變化就更新,沒有變化就從本地取。
有些時候我們的某個頁面會出現問題,或者打開白屏,但是接口沒有問題,頁面也沒有問題,資源也是可以訪問通的,這個時候可能就是cookie太大了,已經超出了原本可控的范圍,我們都知道cookie是會隨着頁面間的跳轉攜帶的,這就肯能導致頁面無法訪問,這種問題不常見,但實際工作中確實會遇到。
可以在頁面中設置cookie白名單,意思就是定期檢查我們的cookie,如果是需要的就保留,不需要的就刪除,定期整理。cookie控制可以減小頁面間傳輸的大小,也可以對cookie進行有效的管理。
服務器緩存配置
當一個文件被瀏覽器加載的時候我們實際上是不知道這個文件是否是過期的,所以瀏覽器和服務器之間存在一種約定,通過header頭的配置,確定文件是否過期。
一般在響應頭中包含一個expires的頭信息,他的值為日期+時間,表示在此時間之后,響應過期,如果數值為0,表示資源已經過期。
當然如果響應頭中包含Cache-Control, 設置了max-age或者s-max-age指令,那么就會忽略expires,而取Cache-Control。
Cache-Control通過制定的指令來實現緩存機制,緩存指令是單向的,這意味着在請求中設置的指令不一定被包含在響應中。他的語法比較簡單,Cache-Control: max-age=秒
設置緩存存儲的最大周期,超過這個時間緩存被認為過期。
ETag是資源版本的標識符,可以讓緩存更搞笑,並節省帶寬,因為如果內容沒有改變,Web服務器不需要發送完整的響應,如果發生了改變,使用ETag有助於防止資源的同時更新相互覆蓋。
ETag類似於指紋,也可能被某些服務器用於跟蹤,比較ETag能快速確定資源是否變更,但也可能被跟蹤服務器永久存留。
ETag: "5c6cccc123-1d45"
Last-Modified是一個響應收不,其中資源包含源頭服務器認定的資源做出修改的日期和時間。他常被用作一個驗證器來判斷接收到的或者存儲的資源是否一致。由於精度比ETag要低,所以這是一個備用機制,包含有if-Modified-Since或If-Unmodified-Since首部的條件請求會使用這個字段。
Date是通用的首部,其中包含了報文創建的日期和時間。
Gzip壓縮
可以對文本進行壓縮,一般是html,css,js,對於非文本不會壓縮,比如說圖片資源,壓縮比率可以達到50%-70%
本地測試開啟https
這個內容不應該寫在這,但是實在不知道寫在哪了。
https這里就不過多介紹了,畢竟不是這篇該有的內容。
瀏覽器目前基本上已經默認開啟了https,所以為了SEO我們也建議使用https,而且https也更加安全。
如果是對外的網站我們需要和經銷商購買ssl證書,可以在gogetssl,ssls.com,sslmate.com中去購買,當然這些證書是有時效的。
如果本地測試的話,也可以在本地安裝一個測試證書,我們可以通過mkcert來實現。首先需要安裝它。
brew install mkcert
安裝根證書
mkcert ---install
生成本地簽名,給123.com
mkcert 123.com
這樣就生成了一對證書,我們可以將這對證書配置在nginx里面,具體配置方法可參考我之前寫的nginx文章。
http2
http2是http的第二版,簡稱h2或h2c,它采用二進制傳輸數據,多路復用,允許通過一個鏈接發起多個請求,所以一般使用h2雪碧圖就沒什么用了,他超出了瀏覽器限制最大連接數的局限,對header頭進行壓縮從而降低傳輸體積,支持服務端推送(server push),可以從服務端將數據推送給客戶端。
開啟HTTP2可以降低服務器壓力,提升網站訪問速度,而且可以更好的保護網站安全因為他是強制使用https的。
開啟http2其實也很簡單,我們需要重新編譯nginx,並且開啟http_ssl_module和http_v2_module
cd nginx-xxx
./configure --with-http_ssl_module --with-http_v2_module
make && make install
同樣這里可以參照之前我寫的nginx文章,其實就是在listen 443端口后添加http2標識。
server {
listen 443 ssl http2;
}
前端的研發流程
首先是技術選型,包括頁面渲染技術和混合式開發技術,然后是項目的初始化,包括React,Vue,Angular,依賴模塊引入,一般會存在一個私有的NPM,接着開始本地開發,方便前端調試和看到效果,項目聯調,產品和設計師對效果進行確認,最后項目整體部署上線。
項目開始之前前后端會指定一些數據接口,有了接口文檔前后端就可以並行開發,前端開發頁面和交互,后端開發業務邏輯。都開發完后前后端開始進行聯調,最后發布上線。
自動化測試
UI自動化,上手比較簡單,不過穩定性較差,常用的工具有appium,他是一個開源的工具用於自動化ios手機,安卓手機還有windows桌面的一個測試工具,robot framework 是基於python可擴展的關鍵字測試框架用於端到端,驗收測試以及測試驅動開發,可用於測試分布式異構應用程序包括可以驗證涉及多種技術的接口,selenium用於web應用程序測試工具可以直接運行在瀏覽器上,可以和用戶的真正操作是一樣的,支持ie, 火狐,谷歌,歐朋等常用瀏覽器,主要用來測試瀏覽器的兼容性。airtest支持自動化的腳本錄制一鍵回收,輕而易舉就能實現自動化測試流程,還是比較常用的。
接口自動化,使用穩定,性價比非常高,工具有java + restassured,是java實現的,輕量級的可以通過編寫代碼向客戶端發送請求並且驗證返回結果。python + requests主要對pthon接口進行測試, JMeter用於對軟件做壓力測試,HttpRunner只需要一份腳本就可以實現自動化測試性能測試,線上監控,持續集成等多種測試的需求。
單元測試,性價比極高,一般由開發完成,但是有一些單元測試框架,Junit5,pytest, unittest。