整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          經(jīng)典面試題-Web前端性能優(yōu)化方法之預加載

          經(jīng)典面試題-Web前端性能優(yōu)化方法之預加載

          昨天的一篇文章《經(jīng)典面試題-Web前端性能優(yōu)化方法之延遲加載》中,我們講到的是延遲加載技術,既然有延遲加載,那么就有預加載,今天這篇文章講述的是預加載如何實現(xiàn)Web性能優(yōu)化。

          loading

          預加載

          預加載技術主要是通過預測瀏覽器在未來某個時間需要用到的資源,提前進行加載,在特定的時間段內(nèi)直接使用即可。作為開發(fā)者,肯定比普通用戶更加了解網(wǎng)頁資源的加載順序,因此通過預加載技術來告知瀏覽器Web中需要用到的核心資源,可以提升網(wǎng)頁的訪問速度。

          預加載技術包括很多個方面,包括DNS prefetching,Preconnect,Prefetch,Subresource,Prerender等,我們一一來看

          DNS prefetching

          DNS prefetching顧名思義,就是提前解析DNS。

          開發(fā)人員可以通過代碼告知瀏覽器盡早的解析特定DNS,當請求該域名下的文件時,就不用再解析DNS,而是可以直接使用該DNS下的文件了。這中方法在使用第三方庫時顯得尤為有效。

          使用方法是,在<head>標簽中添加如下一段代碼

          DNS預加載

          Preconnect

          Preconnect類似于DNS prefetching,它會預先建立TCP握手連接,在需要的時候還會建立TLS連接。

          在現(xiàn)代瀏覽器中,會盡可能的預測網(wǎng)站所需要的連接,通過提前連接,可以消除在真實請求時的DNS解析,TCP連接的時間。

          開發(fā)者可以通過代碼去告知瀏覽器哪些資源是可以提前連接的,代碼段如下

          Preconnect提前連接

          Prefetch

          Prefetch是告知瀏覽器在未來某個時候需要用到的資源,可以提前請求并緩存下來,等到真正需要用的時候,可以直接從緩存中獲取。Prefetch可以預拉取圖片,css,js等資源文件。

          通過以下代碼我們可以實現(xiàn)一張圖片的預拉取并緩存起來。

          Prefetch預拉取

          當然,瀏覽器并不是在任何情況下都會去執(zhí)行預拉取操作,比如在網(wǎng)絡情況不好的情況下不會請求較大的資源,F(xiàn)irefox只會在空閑時去執(zhí)行Prefetch操作。

          Subresource

          Subresource是用來指定加載資源的高優(yōu)先級,使用的方法如下。

          Subresource提前加載

          Subresource與Prefetch不同,Prefetch指定是未來的頁面需要用到的低優(yōu)先級的資源,而Subresource指定的是當前頁面需要用到的高優(yōu)先級的資源。因此,在指定當前頁面中需要用到的資源時,推薦用Subresource,而在后續(xù)頁面中用到的資源提前加載推薦用Prefetch。

          Prerender

          Prerender可以讓瀏覽器提前加載指定頁面上的所有資源。

          Prerender我們可以這樣理解:瀏覽器實際上會在后臺開啟一個隱藏的標簽頁,在這個標簽頁中會下載頁面上需要的所有資源,如果用戶進入了指定的鏈接,則這個隱藏的頁面會立馬顯示出來,而用戶是無法辨別這個頁面是之前的隱藏頁面還是重新開啟的頁面。

          Prerender預加載

          并不是所有的頁面都適合Prerender特性,如果用戶最終未能進入指定的鏈接的頁面,那么提前加載的很多資源文件會浪費很多的帶寬。

          我們可以分析一下一些比較適合使用Prerender特性的頁面:

          • 一個具有分頁展示的圖片集或者文字集,在我們點擊下一頁的時候,可以將下一頁的內(nèi)容使用Prerender屬性預加載

          • 注冊與登錄頁面,新用戶注冊完成之后一般會選擇去登錄,登錄頁面完成之后會跳轉到主頁面,這兩個過程就比較適合Prerender屬性的預加載

          總結

          今天這篇文章主要將的是預加載的Web性能優(yōu)化方式,后面會持續(xù)更新其他Web性能優(yōu)化的文章。

          試經(jīng):懶加載和和預加載。難度:

          什么是懶加載和預加載?請說下什么是懶加載和預加載?

          懶加載和預加載其實都是一種頁面的性能優(yōu)化,都是為了提高網(wǎng)站和應用程序的性能,減少頁面的加載時間。

          其中來說懶加載一般是指在頁面滾動時按需加載頁面上的圖片、視頻或者是其他資源。當頁面加載時只會加載頁面的初始內(nèi)容而不會加載頁面上的所有資源。所以當用戶去滾動頁面的時候再依據(jù)需要去加載對應的資源。這樣就可以減少頁面的加載時間,提高用戶體驗。

          預加載是指在頁面加載時提前加載頁面上的資源,以便在用戶需要時可立即訪問。

          那么預加載是通過頁面中的頭部標簽去使用外部<link>標簽,外鏈樣式以及<script>外部js方式去實現(xiàn)的。可以使用<link>標簽來預加載CSS文件,使用<script>標簽來預載圖片或者是其他資源。

          這樣來說就可以避免在用戶需要的時候再去請求資源,提高響應速度和用戶體驗。

          總體來說懶加載和預加載都是優(yōu)化網(wǎng)站的有效手段,所以我們基本上來說可以根據(jù)具體的場景和需要去選擇合適的方式。

          一般來說懶加載需要去加載大量資源的頁面,就適用于需要去提高響應速度的關鍵資源。我是旭旭,助你面試成功!關注我,助你成功!

          作為直接面向用戶的前端開發(fā)人員,我們都知道頁面首屏打開速度的重要性,直接關系到用戶的留存。

          提升 H5 頁面打開速度的方法也有很多,有從網(wǎng)絡優(yōu)化入手的 CDN、gzip壓縮、Keep-Alive等,有從加載優(yōu)化入手的資源大小優(yōu)化、懶加載、按需加載、代碼拆分、Tree Shaking等,以及頁面渲染時的一些優(yōu)化。 在我們的項目中,上述優(yōu)化基本都有使用,當優(yōu)化達到一定程度,想要繼續(xù)僅基于 H5 自身優(yōu)化已難以再提升,就需要和客戶端合作,提升 H5 頁面的打開速度,比如離線緩存、預加載等。

          這里介紹一個我們使用的接口預請求的方案,它可以相對低成本的提升 FMP (首次有效繪制) 的渲染速度,而且從我們的上線效果上來看提升非常明顯。

          什么是接口預請求

          當我們打開在 APP 內(nèi)的 H5 頁面時,一般會經(jīng)過原生切頁面動畫、創(chuàng)建新頁面、加載 webview、加載 HTML、請求靜態(tài)資源并解析、獲取首屏數(shù)據(jù)、渲染內(nèi)容、下載圖片等步驟。 其實在加載的同時,可以利用 APP 在幫助 H5 獲取首屏數(shù)據(jù),這樣在 H5 頁面加載完成后,可以直接使用 APP 已請求的首屏數(shù)據(jù)進行渲染,這樣就節(jié)省了獲取首屏數(shù)據(jù)的時間。首屏數(shù)據(jù)接口越慢,該方案的價值就越大。

          大體如下圖所示:

          為什么要用接口預請求而不是 SSR?

          在做 H5 秒開優(yōu)化前,我們也討論過 SSR(服務端渲染) 的方案。 基于前后端分離的服務端渲染,一般由前端團隊使用 nodeJS 在服務器進行頁面渲染,前端服務器會組裝一個攜帶了具體數(shù)據(jù)的HTML文本,并且返回給瀏覽器。 服務端渲染雖然可以減少白屏時間,但相較于接口預請求有如下問題:

          1. 需要有完善的基于 nodeJS 的服務器運維、監(jiān)控、告警等支持。這塊是最大問題,大多數(shù)公司的服務端是基于 Java 等,缺乏對 nodeJS 的運維經(jīng)驗,但是由前端團隊來做這一塊支持,對有C 端訪問量的項目也不保險。
          2. 需要更多的服務器負載均衡,消耗更多的服務器自由。而接口預請求計算是在客戶端,不增加服務端復雜度。

          方案

          方案概覽

          既然我們要利用 APP 來幫助 H5 獲取首屏數(shù)據(jù),而我們的 H5 頁面也不止一個,并且每個頁面的參數(shù)都不一樣。 那第一個要解決的問題就是怎么告訴 APP 在打開那些頁面時需要同步請求那些接口,這些接口的入?yún)⑹鞘裁礃拥模?/p>

          當 APP 請求完成后,要解決的第二個問題是怎么把請求結果及時通知給 H5 頁面,并且防止 H5 頁面自身發(fā)起重復請求,增加服務端負擔?

          第三個要解決的是如果 H5 修改了代碼,更新了參數(shù),而告知 APP 入?yún)⒌呐渲眠€未更新,怎么避免使用舊配置請求的結果?

          我們先帶著問題看下整個方案的流程圖:

          如何讓APP 知道打開那些頁面時需要預請求,請求什么接口,什么參數(shù)

          H5 項目接口預請求配置

          我們在每個 H5 項目先新增的另一個叫 app.config.json 的配置文件,配置了該頁面需要請求的主接口(可以是多個),請求方法、header、body、url 參數(shù)等。

          單個頁面配置:

          json復制代碼{    
              pageName: '頁面名稱',
              key: 'H5頁面的URL',   //頁面唯一路徑,作為key
              preRequest: {        // 接口預請求配置
                  appVersion: '8.0.1', // 支持app最低版本號,為了處理APP識別字段新增等變更情況
                  support: 0,      // 是否支持接口預請求,0 | 1
                  apis:[           // 預請求接口信息,數(shù)組
                      {
                          fragment: "#/detail", // 新增fragment 指定對應的路由(hash模式)頁面
                          url: 'https://xxxx/api/address', // 請求url
                          method: 'get',                      // 請求類型,如get|post,不傳默認get
                          header: {},                         // 請求頭,規(guī)則同請求體
                          body:{                              // 請求體
                              shopId: "getUserInfo.shopId:String|''",
                              cityId:'getLocation.cityId:Int',
                              key5:'params.orderId',
                              key6:'params.xxx'
                          }
                      }
                  ]
              }
          }

          如上配置,頁面 URL、接口地址等都好理解。 在打開一個 H5 時,接口的入?yún)⒁话銇碜詢蓚€地方,最常見的是通過 URL 來獲取,另一種常見情況是通過 JSBridge 在 APP 內(nèi)獲取,比如全局的用戶信息等。 這里我們通過不同的字符串告知 APP 需要從哪里獲取那些參數(shù),比如 params.orderId 是告知 APP 需要從打開 H5 頁面的URL 中獲取 orderId 的參數(shù),而 getUserInfo.shopId,則是告知 APP 需要通過 JSBridge 中的 getUserInfo 方法獲取 shopId 參數(shù)。 這里APP并非真的去自己調(diào)用 JSBridge 的方法,而是告知 APP 該值需要和 JSBridge 中的方法達到同樣的效果。

          也可以傳遞固定值,比如接口請求中入?yún)?type 是固定值 1,只需要和 APP 商議好規(guī)范,讀取識別即可。 以上我們解決了 APP 請求那些接口以及參數(shù)的問題。

          配置文件如何下發(fā)給 APP

          我們再 H5 打包構建時對 app.config.json 進行處理,在增加些其他必備配置后,提交到 H5配置平臺,這時可以選擇在打開 APP 時調(diào)配置平臺的接口,但每次都讀取數(shù)據(jù)庫中的配置,會給服務端帶來極大的壓力。

          這里我們做了一個小小的優(yōu)化,來很好的規(guī)避了這個問題。 我們再構建完成,發(fā)布上線后,在 H5配置平臺 打開預請求的開關時,由配置平臺讀取所有配置的頁面,生成一個配置的 JSON 文件,文件名類似 h5config.xxx.json,xxx 代表版本號,并把配置文件上傳到 CDN。 用戶打開 APP 時,通過接口下發(fā)最新配置文件的 地址和版本,APP 本地和緩存的文件對比,判斷是否要下載最新的配置文件。

          這樣改造后,只需要在點擊發(fā)布的那一刻,讀庫生成新配置文件,大量的 C 端用戶訪問時,只需要調(diào)一個簡單的接口獲取最新配置版本和地址即可。

          最終的配置文件類似這樣:

          json復制代碼{
              version: "0.0.1",
              global:{
                  // 全局配置
              },
              pages: [
                  {
                      key: "https://xxx.com/pages/xxx.html", 
                      pageName: "XXX活動頁", 
                      openImageCache: 0, // 是否開啟圖片緩存,0關閉,1開啟 
                      openPreRequest: 1, // 是否開啟接口預請求,0關閉,1開啟 
                      config: {
                          // 上面的單個頁面配置生成而來
                      }
                  }
              ]
          }

          APP 每次打開 H5 頁面,都從配置中排查,是否有配置的頁面 URL,如果有并且打開了接口預請求,則在打開 H5 頁面的同時基于配置發(fā)起接口請求。

          至此就解決了我們的第一個問題。

          如何同步請求結果并避免 H5 重復請求

          最初我們想到的是通過 JSBridge 去輪循獲取 APP 中請求的數(shù)據(jù),但這種方式顯然不夠優(yōu)雅。 后來通過 APP 在獲取到結果,并且 webview 觸發(fā)“onLoad ”事件后,把數(shù)據(jù)注入到 window 對象下。

          如圖所示,正常情況下,存在兩種情況:

          1. H5 頁面尚未加載好,數(shù)據(jù)就已返回
          2. H5 頁面加載完成后,數(shù)據(jù)尚未返回

          不管是哪種情況,我們都可以通過監(jiān)聽 注入的 window 對象,來獲取數(shù)據(jù),當?shù)谝淮螞]有讀取到時,會立即發(fā)起 H5 本身的請求,這樣即使接口預請求異常也不影響 H5 本身。 對于 window 對象我們通過 Object.defineProperty 進行監(jiān)聽,APP 和 H5 自身的請求誰先返回就用誰。

          這樣就解決了第二個問題,既能提升又完全不影響 H5 自身業(yè)務。

          如何獲取到正確的數(shù)據(jù)

          上文我們提到,因為 H5 可以隨時發(fā)版,發(fā)版后,如果沒有及時更新配置文件,或者更新了但 APP 有緩存,沒有立即使用最新的配置文件。 此時如果 H5 本身的參數(shù)變化了,APP 還是按舊配置獲取請求,得到的數(shù)據(jù)并非新版本的數(shù)據(jù)時如何處理了?

          還記得前面提到注入的 window.request_cache_xxx 對象嗎,其中 xxx 是配置中 url、method、header、body、params(params 是指參數(shù)掛載在 URL 上)這些字符串的 md5 值,每個H5 項目每次更新配置都有一個唯一的 md5 值。其中 H5 本地保留一份,另一份通過配置文件下發(fā)給APP,如果兩邊的 md5 值匹配不上,則 H5 不會使用 APP 注入的數(shù)據(jù)。

          這里其實還有另一個風險。 如果 H5 開發(fā)者在代碼中的參數(shù)和配置文件不同步,比如迭代時間長后,忘記需要更新配置文件了。那么也就出現(xiàn)悲劇。 作為技術方案設計者,我們不能依賴人員的謹慎性,而應該靠系統(tǒng)設計來規(guī)避這些問題。

          能發(fā)生的事情終將會發(fā)生

          在這里我們通過修改 H5 項目的 HTTP 公共庫,使其在開發(fā)和測試環(huán)境都是通過讀取 app.config.json 中配置的接口、參數(shù)等來發(fā)起請求,這樣就做到開發(fā)調(diào)試和線上一致。

          以上我們就解決了 APP 請求數(shù)據(jù)的正確性問題。

          最終效果

          通過以上方案,我們基本上沒有借助其他部門的力量,單單依靠大前端組內(nèi)的資源,就極大解決了 H5 秒開的問題。 通過我們的性能監(jiān)控的數(shù)據(jù),在開啟 H5 秒開后包含接口預請求、DNS 預請求(通過 APP 對 H5 使用到的域名進行 DNS 緩存)策略后,所有 H5 項目,F(xiàn)MP 達到 1.2 秒的超過 80%。

          PS:FMP 我們?nèi)〉氖菑挠脩粼?APP 點擊 H5 鏈接到主內(nèi)容渲染完成的時間

          絕大部分頁面有 200~600ms 的提升,主要使用的 CMS 活動頁,安卓提升了 27%,iOS 提升了 43%,平均 FMP 在 900ms 左右。

          視頻對比

          作者:思考的Joey 鏈接:https://juejin.cn/post/7339846378125033523


          主站蜘蛛池模板: 精品国产AⅤ一区二区三区4区| 中文字幕在线播放一区| 人妻视频一区二区三区免费| 亚洲AV无码一区二区乱子仑| 后入内射国产一区二区| 无码人妻一区二区三区在线| 无遮挡免费一区二区三区| 自慰无码一区二区三区| 国产一区二区三区在线| 亚洲一区二区三区亚瑟| 国产伦理一区二区| 国产伦精品一区二区三区视频猫咪| 亚洲AV噜噜一区二区三区| 无码精品视频一区二区三区| 精品人体无码一区二区三区 | 香蕉久久AⅤ一区二区三区| 蜜臀Av午夜一区二区三区| 国产精品亚洲高清一区二区 | 波多野结衣AV无码久久一区| 日韩精品一区二区三区在线观看l| 无码aⅴ精品一区二区三区浪潮| 国产一区二区免费在线| 一本一道波多野结衣一区| 精品三级AV无码一区| 国模少妇一区二区三区| 亚洲午夜日韩高清一区| 国产一区二区三区在线观看免费| 波多野结衣久久一区二区| 91福利一区二区| 亚洲国产精品自在线一区二区| 成人日韩熟女高清视频一区| 国产一区二区精品久久岳| 精品乱子伦一区二区三区| 久久婷婷色综合一区二区| 亚洲高清成人一区二区三区| 一区二区三区免费看| 一区二区三区四区电影视频在线观看 | 国产一区二区三区免费视频| 五十路熟女人妻一区二区| 无码播放一区二区三区| 欧美日韩精品一区二区在线观看|