你不知道的 Web 性能優(yōu)化 | 原力計劃-重拳出擊

你遇到過打開一個網(wǎng)站需要10秒以上的嗎舱禽?這種網(wǎng)頁響應非常緩慢避凝,占用大量的CPU和內(nèi)存舞萄,瀏覽起來常常有卡頓,頁面的動畫效果也不流暢管削。你會有什么反應倒脓?我猜想,大多數(shù)用戶會關(guān)閉這個頁面含思,改為訪問其他網(wǎng)站崎弃。作為一個開發(fā)者甘晤,肯定不愿意看到這種情況,那么怎樣才能提高性能呢饲做?

有興趣的同學可以去我的GitHub线婚,里面有我的分享的學習過程和blog:github.com/193Eric。

使用Web Worker

Web Worker 是HTML5 提供的一個Javascript多線程解決方案艇炎,運行在瀏覽器后臺酌伊。如我們所知js是個單線程的,js引擎在運行js的時候缀踪,不能干其他事。不過在使用中需要注意以下幾點:

它是一種JavaScript 工作線程虹脯,不能直接訪問DOM

能發(fā)送網(wǎng)絡請求驴娃。

它在不用時會被中止,并在下次有需要時重啟

在開發(fā)過程中循集,可以通過 localhost 使用服務工作線程唇敞,但如果要在網(wǎng)站上部署服務工作線程,需要在服務器上設(shè)置 HTTPS咒彤。

Worker 線程無法讀取本地文件疆柔,即不能打開本機的文件系統(tǒng)(file://),它所加載的腳本镶柱,必須來自網(wǎng)絡旷档,這樣做主要是為了安全,因為是可以通訊的歇拆,如果被別人修改了文件鞋屈,引入了本地的js,進行通訊就會出現(xiàn)問題故觅,所以只能訪問同源的網(wǎng)絡文件厂庇。(重點,所以本地調(diào)試的時候需要開啟服務输吏,用node或者后臺語言啟動

web Worker 與主線程的交互速度

我們用代碼來看下從主線程 --> web worker --> 主線程 最簡單的需要多長時間权旷。

webWorker

var?worker?=?new?Worker("worker.js");

console.log(new?Date().getTime())?//?開始時間

worker.postMessage("123456")

worker.onmessage?=?function?(e)?{

console.log(new?Date().getTime())?//?接收時間

}

</script>

</body>

<html>


//webWorker.js

onmessage=function(evt){

vard=evt.data//通過evt.data獲得發(fā)送來的數(shù)據(jù)

postMessage(d)//將獲取到的數(shù)據(jù)發(fā)送會主線程

}

經(jīng)過幾次測試,大概的事件在30-50ms之間(當然這個值會隨著機器性能問題有大有泄峤Α)拄氯,正常的傳輸速度是很快的。

web Worker 優(yōu)化策略與實踐

案例:大量的js計算(fibonacci數(shù)列計算)

varworker=newWorker("worker.js");

letbeginTime=newDate().getTime()

console.log(beginTime)

letfibonacci=(n)=>{

returnn<2?n:fibonacci(n-1)+fibonacci(n-2);

};

fibonacci(45)

letendTime=newDate().getTime()

console.log(`${endTime}---------歷時${(endTime-beginTime)/1000}s`)

我們在主線程計算fibonacci(45)看看需要多少時間盗迟,在計算的時候頁面是卡主的坤邪,會非常影響用戶體驗。

然后我們看看放在web worker里面是什么情況罚缕。

//index.htmlvarworker=newWorker("worker.js");letbeginTime=newDate().getTime()console.log(beginTime)worker.postMessage("fibonacci");worker.onmessage=function(e){letendTime=newDate().getTime()console.log(e,`${endTime}---------歷時${(endTime-beginTime)/1000}s`)};console.log("working")console.log("working")console.log("working")

//worker.jsonmessage=function(evt){vard=evt.data;//通過evt.data獲得發(fā)送來的數(shù)據(jù)letfibonacci=(n)=>{returnn<2?n:fibonacci(n-1)+fibonacci(n-2);};letdata=fibonacci(45)postMessage(data);//將獲取到的數(shù)據(jù)發(fā)送會主線程}

可以看到艇纺,計算的時間是差不多的,但是并沒有阻礙頁面的運行。所以黔衡,一些高計算耗費時間的功能蚓聘,可以放到web worker中計算完成后再返回回來。

SPA項目首頁白屏問題

現(xiàn)在三大框架(vue,react,angular)的興起盟劫,越來越多的項目采用SPA這種接近原生app體驗的架構(gòu)方式夜牡。采用SPA模式,就意味著侣签,首頁或者main.js過大塘装,首屏加載的速度會受到很大的限制。會存在一定時間的白屏影所。

SPA項目因為html都是js去生成的(虛擬Dom原理)蹦肴,所以在js沒有執(zhí)行加載完之前,dom是不會有的猴娩。一開始客戶端從服務端獲取到html只是一個空殼阴幌,所以會顯示白屏。

下面列出一些解決方案:

1.服務端渲染SSR(加快首屏加載和SEO)

SSR是一個可以有效的提高首屏渲染速度的方法卷中,之后我會開單張去單獨實踐服務端渲染矛双。

2.預渲染

預渲染是一個方案,使用爬蟲技術(shù)蟆豫。由于我們打包過后的都是一些js文件议忽,使用一些技術(shù)(puppeteer)可以爬取到項目在chrome瀏覽器展示的頁面,然后把它寫入js,和打包文件一起无埃。類似prerender-spa-plugin

不過這種技術(shù)的缺點也很明顯徙瓶,我們在打包過程中,所展示的頁面是當時環(huán)境下的數(shù)據(jù)嫉称,也就是說如果首頁有很多的動態(tài)獲取的數(shù)據(jù)(比如說實時的股票價格)侦镇,那如果采用這種方案,用戶第一眼看到并不是當時數(shù)據(jù)织阅,會認為是個錯誤信息壳繁。

3.骨架屏(占位塊和圖片)

骨架屏可以說現(xiàn)在比較實用的首屏優(yōu)化技術(shù)了,方便也不是很復雜荔棉。骨架屏類似于app的啟動頁闹炉,一般我們進入app都會有宣傳的啟動頁,然后才看到首頁润樱。骨架屏就是這樣渣触,用戶進來首先看到的是骨架屏,然后首頁渲染完之后壹若,再把骨架屏干掉嗅钻。

骨架屏主要有兩種方式可以完成:

通過編譯的時候自動生成還是puppeteer(上面說了預渲染也用皂冰,它主要是能在代碼里面喚起chrome瀏覽器,或者后臺喚起养篓,也就是沒有彈出瀏覽器秃流,但是可以獲取到真實瀏覽器中渲染的內(nèi)容),有了它我們就能獲取到瀏覽器里面的dom元素柳弄,然后通過對頁面中元素進行刪減或增添舶胀,對已有元素進行修改生成我們想要的骨架,然后將修改后的 HTML 和 CSS 樣式提取出來碧注,這樣就是骨架屏了嚣伐。當然遇到了圖片的話,還是需要轉(zhuǎn)成svg的形式萍丐,或者base64這樣就不需要網(wǎng)絡請求了纤控。

通過設(shè)計圖+布局這是一種直接重新寫一個頁面的方式,圖片的話采用svg和base64的形式碉纺,生成一個dom,解析注入到服務器返回的index.html里面(ssr render注入)。

現(xiàn)在網(wǎng)絡上的項目刻撒,最能提現(xiàn)的就是餓了么的h5了骨田,我們可以通過手機瀏覽器打開餓了么。

我們首先看到是骨架屏声怔,然后過一會才會看到首屏态贤,這就是餓了么用了這種技術(shù),很大的提高了用戶的體驗醋火。page-skeleton-webpack-plugin項目地址:https://github.com/ElemeFE/page-skeleton-webpack-plugin

SSL延遲有多大悠汽?

我們知道http是經(jīng)過TCP三次握手就可以成功通訊 。再來看Https鏈接芥驳,它也采用TCP協(xié)議發(fā)送數(shù)據(jù)柿冲,所以它也需要上面的這三步握手過程。而且兆旬,在這三步結(jié)束以后假抄,它還有一個SSL握手。

HTTP耗時 = TCP握手 ; HTTPS耗時 = TCP握手 + SSL握手

在研究ssl延遲之前丽猬,我們先來學一個命令行工具curl宿饱,-w,–write-out參數(shù)。顧名思義脚祟,write-out的作用就是輸出點什么谬以。curl的-w參數(shù)用于在一次完整且成功的操作后輸出指定格式的內(nèi)容到標準輸出。

主要了解下幾個參數(shù):

http_code http狀態(tài)碼

time_total 總時間由桌,按秒計为黎。

time_namelookup DNS解析時間,從請求開始到DNS解析完畢所用時間

time_connect 連接時間,從開始到建立TCP連接完成所用時間,

time_appconnect 連接建立完成時間邮丰,如SSL/SSH等建立連接或者完成三次握手時間。

我們主要用time_connect(TCP握手的耗時)碍舍,time_appconnect(SSL握手的耗時)

終端輸入curl -w "TCP握手的耗時: %{time_connect}, SSL握手的耗時: %{time_appconnect}\n" -so /dev/null https://www.taobao.com

我們可以看到ssl耗時是tcp的三倍左右柠座,具體數(shù)字取決于CPU的快慢和網(wǎng)絡狀況。

所以片橡,如果是對安全性要求不高的場合妈经,為了提高網(wǎng)頁性能,建議不要采用保密強度很高的數(shù)字證書捧书。

防抖節(jié)流那些事

在開發(fā)過程中我們很多時候會碰到需要防抖和節(jié)流去解決問題吹泡。不要小看它們,沒有它們的話经瓷,特定情況下的會造成很大的性能阻塞爆哑。

防抖(當持續(xù)觸發(fā)事件時,一定時間段內(nèi)沒有再觸發(fā)事件舆吮,事件處理函數(shù)才會執(zhí)行一次)防抖我們可以理解為揭朝,存在一個scroll事件,只要滾動就會觸發(fā)handler回調(diào)函數(shù)色冀,防抖的處理是潭袱,等scroll事件完全停下來1000ms(這個值自行設(shè)定)之后,再出觸發(fā)handler函數(shù)锋恬。

節(jié)流(當持續(xù)觸發(fā)事件時屯换,保證一定時間段內(nèi)只調(diào)用一次事件處理函數(shù))節(jié)流顧名思義,觸發(fā)scroll事件的時候与学,并不立即執(zhí)行handle函數(shù)彤悔,每隔1000ms(這個值自行設(shè)定)才會執(zhí)行一次handle函數(shù)

區(qū)別:節(jié)流是每一個時間段之后就會觸發(fā)一次,存在間隙的連續(xù)觸發(fā)索守,而防抖不一樣晕窑,只會在最后才觸發(fā)一次。

重排與重繪的相愛相殺

從前面的文章(瀏覽器渲染過程剖析)已經(jīng)學到了網(wǎng)頁的生成過程蕾盯。

HTML代碼轉(zhuǎn)化成DOM

CSS代碼轉(zhuǎn)化成CSSOM(CSS Object Model)

結(jié)合DOM和CSSOM幕屹,生成一棵渲染樹(包含每個節(jié)點的視覺信息)

生成布局(layout),即將所有渲染樹的所有節(jié)點進行平面合成

將布局繪制(paint)在屏幕上

1-3步都很快级遭,耗時的是第四步和第五步望拖。這兩步合稱”渲染“,在網(wǎng)上生成的過程中,網(wǎng)頁至少會渲染一次挫鸽。

有三種情況會導致瀏覽器重新渲染:

1.修改DOM

2.修改樣式表

3.用戶事件(比如鼠標懸停说敏、頁面滾動、輸入框鍵入文字丢郊、改變窗口大小等等)

重新渲染盔沫,就需要重新生成布局和重新繪制医咨。前者叫做"重排"(reflow),后者叫做"重繪"(repaint)架诞。

重排和重繪不斷的觸發(fā)拟淮,是影響網(wǎng)頁性能低下的根本原因。提高網(wǎng)頁性能谴忧,就是要降低"重排"和"重繪"的頻率和成本很泊,盡量少觸發(fā)重新渲染。重排必定會重繪沾谓,而重繪不一定重排委造。

最后

喜歡小編的可以點個贊關(guān)注小編哦,小編每天都會給大家分享文章均驶。

我自己是一名從事了多年的前端老程序員昏兆,小編為大家準備了新出的前端編程學習資料,免費分享給大家妇穴!

如果你也想學習前端爬虱,加入此Q群:950919261

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腾它,隨后出現(xiàn)的幾起案子饮潦,更是在濱河造成了極大的恐慌,老刑警劉巖携狭,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異回俐,居然都是意外死亡逛腿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門仅颇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來单默,“玉大人,你說我怎么就攤上這事忘瓦「槔” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵耕皮,是天一觀的道長境蜕。 經(jīng)常有香客問我,道長凌停,這世上最難降的妖魔是什么粱年? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮罚拟,結(jié)果婚禮上台诗,老公的妹妹穿的比我還像新娘完箩。我一直安慰自己,他們只是感情好拉队,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布弊知。 她就那樣靜靜地躺著,像睡著了一般粱快。 火紅的嫁衣襯著肌膚如雪秩彤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天皆尔,我揣著相機與錄音呐舔,去河邊找鬼。 笑死慷蠕,一個胖子當著我的面吹牛珊拼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播流炕,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼澎现,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了每辟?” 一聲冷哼從身側(cè)響起剑辫,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渠欺,沒想到半個月后妹蔽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡挠将,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年胳岂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舔稀。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡乳丰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出内贮,到底是詐尸還是另有隱情产园,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布夜郁,位于F島的核電站什燕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏竞端。R本人自食惡果不足惜秋冰,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望婶熬。 院中可真熱鬧剑勾,春花似錦埃撵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捂刺,卻和暖如春谣拣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背族展。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工森缠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仪缸。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓贵涵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親恰画。 傳聞我的和親對象是個殘疾皇子宾茂,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 你害怕與人交際嗎跨晴?你是那個碰見人就會躲的人嗎?在與人交流的過程中片林,你是否常常會尷尬到不知道說什么端盆。 其實,沒有人喜...
    譯耳閱讀 1,482評論 1 29
  • 喜歡最近的八點鐘 夕陽西下
    zxy我在等你閱讀 156評論 0 0
  • 一個普通人费封,怎么做對社會有價值爱谁。小文的話讓我一下子清晰了。 做好自己孝偎,用自己的身體力行,影響身邊的人凉敲。取得一定的成...
    56東南西閱讀 247評論 0 0