1. 程式人生 > >簡單A/BTest驗證圖片懶載入效果

簡單A/BTest驗證圖片懶載入效果

文章結構

文章基本思路:“目的 => 方案 => 驗證 => 總結啟發

一,圖片懶載入實現
二,預期效果
三,A/BTest驗證
四,總結

一,圖片懶載入實現

方案選擇

圖片懶載入的本質是將某一圖片的載入推遲到使用者看到或即將看到該圖片的時候。實現圖片懶載入目前有三種方案:

方案 具體描述 缺點
一. 小程式image元件的lazy-load屬性 ①不支援配置(載入時機,預載入數量) ②僅在page和scroll-view中生效(意味著很難通用)
二,頁面滾動監聽 小程式頁面監聽頁面滾動(onPageScroll),滾動時逐一比較圖片節點的top值(可由wx.createSelectorQuery().select('yourselector’).boundingClientRect((ret)=>{}).exec()
獲得)與滾動位置的關係
監聽滑動 & 遍歷所有節點會對滾動效能產生一定的影響(如果節點從上到下遍歷,能做一些優化,也能達到較好的效果
三,IntersectionObserver 採用IntersectionObserver API,交由瀏覽器核心底層判斷圖片是否與視窗相交,減少核心層與js層的跨程序通訊,效能更好(小程式基礎庫1.9.3開始支援) 不相容低版本瀏覽器核心

補充:
①除了方案一,方案二三都同時支援小程式和H5,這裡僅以小程式為例。
②如有別的方案歡迎分享補充_

基於上面的方案分析和當前使用者系統佔用率分佈(IntersectionObserver API支援率大於80%),我決定採用

IntersectionObserver API來對當前專案做漸進式增強,後續隨著使用者裝置更新,將能實現100%的優化覆蓋。

方案實現

參考效能更優越的小程式圖片懶載入方式,感謝分享!注意:原文章方案存在Android快速滾動到底部沒有觸發載入 的問題。

從前面的視訊我們可以看到,優化的物件是商品詳情圖片列表,考慮到複用性,我把圖片列表封裝成lazyload-list元件,原始碼如下:

/**
 * lazyload-list
 * imgs: 圖片連結陣列,
 * lazyload: 是否開啟lazyload功能,預設開啟
 * <lazyload-list imgs="{{intros}}"></lazyload-list>
 */
Component({ properties: { imgs: { type: Array, value: [], }, lazyload: { type: Boolean, value: true, } }, data: { lazyImgs: [], classNote: 'lazy-img-' }, ready: function() { // 介面相容性判斷,不支援新特性則回退到即時載入的方案 if (!this.createIntersectionObserver) { // @TODO 可以改用基於滾動檢測 & 高度判斷的實現方案 this.setData({ lazyload: false }); } else { var lazyImgs = []; this.data.imgs.forEach(function(img) { lazyImgs.push({ url: img, loaded: false }) }); this.setData({ lazyImgs: lazyImgs }); this.lazyloadImg(); } }, methods: { // 說明:原方案用同一個observer監聽第一張圖片載入,然後再監聽下一張圖片載入, // 但在安卓系統下極快速滑動會出現第二張圖片沒有觸發載入就跳到後面的圖片的情況,導致後面的圖片都載入不出來。 // 因此為了穩妥起見,給每一張圖片設定單獨的observer。 lazyloadImg: function () { var that = this; this.data.lazyImgs.forEach(function(img, i) { var intersectionObserver = that.createIntersectionObserver(); var observeSelector = '.' + that.data.classNote + i; // css選擇器 // bottom:300 指距離底部以下300px即會觸發事件 intersectionObserver.relativeToViewport({bottom: 300}).observe(observeSelector, function(res) { intersectionObserver.disconnect(); img.loaded = true; that.setData({ ['lazyImgs['+ i +']']: img }) }) }); } } })
<view>
	<view wx:for="{{lazyImgs}}" wx:key="{{item}}" class="{{classNote + index}}">
		<image class="img" mode="widthFix" src="{{lazyload && !item.loaded ? '' : item.url}}"/>
	</view>
</view>


.img {
	width: 100%;
	display: block;
}

實現過程

  1. 根據傳入的圖片連結陣列渲染image標籤:
    1. 設定src為空;
    2. 設定唯一的class(用於查詢到唯一的標籤,新增監聽);
  2. 在DOM渲染完成後(ready事件),新增IntersectionObserver監聽:
    1. 介面相容性判斷,向後相容;
    2. 根據上面設定的唯一class找到DOM節點,給所有圖片DOM節點新增IntersectionObserver監聽;
  3. 使用者滾動(或者一進到頁面就看到了圖片)觸發新增IntersectionObserver回撥,載入圖片
    1. 設定當前圖片連結,載入圖片;
    2. 刪除當前節點監聽;

補充-體驗相關:圖片應設定預設寬高(小程式本身有設定),圖片載入前後高度變化儘可能小一些,對頁面結構影響相對小,給使用者觀感會好很多。

二,預期效果

圖片懶載入主要節省了使用者沒看到的圖片的載入流量,節省流量在邏輯上是可以預期的。

但不同業務,不同場景使用者的瀏覽情況不一樣,例如當用戶想買這個商品時,一般會認真瀏覽所有的商品圖片,這個時候是會載入完所有的圖片的,當然使用者也沒有浪費流量。而當用戶只是從列表頁點進來看看簡單的介紹時,使用者往往不會看商品詳情圖片,或者說不會看完所有的,那這部分沒有顯示圖片的流量就能被節省下來。

邏輯推匯出來的效果沒有問題,符合預期。下面我們來看看在線上產品中的效果如何:到底能為使用者節省多少流量?

三,A/BTest驗證

對比驗證

核心在於控制變數法。

為了知道使用圖片懶載入列表元件**“到底能為使用者節省多少流量”,我們需要對比優化策略上線前後平均每個使用者在商品詳情頁花費的流量多少**。

簡化到方便統計:

  1. 平均每個使用者在商品詳情頁花費的流量
  2. 平均每個使用者在商品詳情頁瀏覽的圖片數量(假設每張圖片的大小一致,實際上是30k~150k/張)
  3. 平均每個使用者在商品詳情頁載入的圖片比例(抹平不同商品詳情頁圖片數量不一樣的差異)
  4. 結論推導:如果圖片載入比例在應用了優化策略後下降很多,說明圖片懶載入優化能節省使用者大量流量,如果下降不多,證明該業務該場景下實際優化意義不大。

傳統方法

先統計原來一週內“平均每個使用者在商品詳情頁載入的圖片比例”,再統計圖片載入優化策略上線後接下來一週內載入比例,進行對比,共耗時兩週。(取完整一週作為統計週期是為了排除時間因素帶來的影響)

實際統計過程如下:

  1. 給所有image標籤繫結bindload事件,圖片載入完成後計數 + 1;
  2. 離開頁面前(onUnload,onHide / 或別的觸發頁面跳走的事件),計算載入比例 = 圖片載入數量 / 圖片總數
  3. 上報該比例;
  4. 後臺統計:平均圖片載入比例 = 所有上報載入比例之和 / 上報次數

高效的A/BTest

A/BTest相信大家都理解,A/BTest的核心優勢在於能在線上並行測試多個方案。例如上面為了獲取前後兩個圖片載入比率,我們需要耗時兩週,而如果採用A/BTest,隨機將使用者分成兩半,一半執行原有的圖片載入策略,一半執行優化後的圖片載入策略,我們只需要耗費一週就能得到我們想要的結果。

兩週 => 一週 是A/BTest給我們帶來最直觀的收益,畢竟時間先機對於網際網路公司的重要性不用再多說,而A/BTest因其並行性帶來測試環境更加相似的特點則能減少別的無關因素影響(例如這一週沒有搞活動,下一週確搞了運營活動,統計資料可能會產生誤差),A/BTest更多相關內容請參考資料分析領域的沉澱,我就不班門弄斧了。

** 真的需要A/BTest嗎?**看到這裡說不定有同學已經發現,上面這個優化對比,根本不需要測兩個圖片載入比例,因為優化前的圖片載入比例就是100%(全載入),因此根本用不上A/BTest,光測優化後的圖片載入比例就行。說得很對!這個優化比較簡單,理論上也能直觀推匯出結果。但如果是要在這個圖片方案上做調整,例如對比上面提到的方案二,我們就不能直觀推匯出結果了,此時A/BTest將能發揮重要作用!

統計過程和上面傳統方法的類似,就不贅述了,區別僅在於上報的時候加上引數來區分兩種圖片載入方案,下面重點說說:

簡單的A/BTest實現 - 隨機選取使用者開啟圖片載入優化:

  1. 頁面載入時,Math.random() > 0.5將使用者隨機分成兩半;
  2. 將該使用者型別記錄進cookie裡,避免下次進來再次被分組;
  3. 一般使用者開啟lazyload;
  4. 統計上報;
/**
 * lazyload-list
 * imgs: 圖片連結陣列,
 * lazyload: 是否開啟lazyload功能,預設開啟
 * preloadCount: 預載入圖片數量
 * <lazyload-list imgs="{{intros}}"></lazyload-list>
 */
Component({
  properties: {
	  imgs: {
		type: Array,
		value: [],
	  },
	  lazyload: {
		type: Boolean,
		value: true,
	  },
	  preloadCount: {
		  type: Number,
		  value: 1
	  }
  },
  data: {
	lazyImgs: [],
	classNote: 'lazy-img-',
	loadedCount: 0 // 圖片載入數量統計
  },
  ready: function() {
	  // A/BTest: 隨機選取使用者
	  var key = 'lazyloadUserType';
	  var userType = wx.getStorageSync(key);
	  if (!userType) {
		  // 設定使用者型別
		  var lazyloadOn = Math.random() > 0.5;
		  userType =  lazyloadOn ? 'lazy' : 'normal';
		  wx.setStorageSync(key, userType);
	  }
	  // 根據使用者型別啟用不同載入策略
	  if (userType === 'lazy') {
		  // 介面相容性判斷,不支援新特性則回退到即時載入的方案
		  if (!this.createIntersectionObserver) {
			  // @TODO 可以改用基於滾動檢測 & 高度判斷的實現方案
			  this.setData({ lazyload: false });
		  } else {
			  var lazyImgs = [];
			  this.data.imgs.forEach(function(img) {
				  lazyImgs.push({
					  url: img,
					  loaded: false
				  })
			  });
			  this.setData({ lazyImgs: lazyImgs });
			  this.lazyloadImg();
		  }
	  } else {
		  this.setData({ lazyload: false });
	  }
  },
  detached: function() {
	  // 圖片載入比例計算
	  var loadRate = (this.data.loadedCount/this.data.imgs.length).toFixed(4);
	  // console.log(loadRate);
	  // 資料上報
  },
  methods: {
	  // 說明:原方案用同一個observer監聽第一張圖片載入,然後再監聽下一張圖片載入,
	  // 但在安卓系統下極快速滑動會出現第二張圖片沒有觸發載入就跳到後面的圖片的情況,導致後面的圖片都載入不出來。
	  // 因此為了穩妥起見,給每一張圖片設定單獨的observer。
	  lazyloadImg: function () {
		  var that = this;
		  this.data.lazyImgs.forEach(function(img, i) {
			  var intersectionObserver = that.createIntersectionObserver();
			  var observeSelector = '.' + that.data.classNote + i; // css選擇器
			  // bottom:300 指距離底部以下300px即會觸發事件
			  intersectionObserver.relativeToViewport({bottom: 300}).observe(observeSelector, function(res) {
				  intersectionObserver.disconnect();
				  img.loaded = true;
				  that.setData({
					  ['lazyImgs['+ i +']']: img
				  })
			  })
		  });
	  },
	  onImgLoad: function (e) {
		  // 圖片載入數量統計
		  this.data.loadedCount += 1;
	  }
  }
})

四,總結啟發

經過一週的統計分析,使用圖片懶載入列表元件後,圖片載入比例:

// 2018-11-09~11-11線上資料

100% => 58% ↓42%

以上僅是特定專案特定頁面的統計資料,僅供大家參考。

總結

從結果資料可以看到圖片懶載入是web流量優化的基礎,尤其是在長圖片列表有明顯的差異。應該將列表圖片懶載入優化看做雪碧圖壓縮這種基礎優化,有助於提升web應用的整體表現。

優化雖不復雜,但“確定目標,方案分析選擇,預期推導,A/BTest驗證,決策”這個方法能穩妥地解決問題。

啟發

也叫TodoList,或者社群說法,挖坑。
需求繁忙,期待學有餘力的朋友們共同探索。

  1. 採用方案二覆蓋低版本機型 - 開源社群以及有很多版本;
  2. 封裝純js邏輯,方便swiper等元件實現圖片懶載入;
  3. 學習現成的A/BTest系統:技術賦能產品做決策;

相關推薦

簡單A/BTest驗證圖片載入效果

文章結構 文章基本思路:“目的 => 方案 => 驗證 => 總結啟發” 一,圖片懶載入實現 二,預期效果 三,A/BTest驗證 四,總結 一,圖片懶載入實現 方案選擇 圖片懶載入的本質是將某一圖片的載入推遲到使用者看到或即將看到該圖

原生javascript圖片載入效果程式碼。

原理是先獲取頁面所需懶載入的所有圖片物件,然後分別計算圖片距離頂部的距離是否小於螢幕可見高度+頁面滾動高度,即元素是否從下滾動到眼球可見位置,如果小於,那麼將自定義的data-src屬性中的值(即圖片的

如何結合外掛 vue-lazyload 來簡單實現圖片載入

外掛地址:https://www.npmjs.com/package/vue-lazyload; 一、使用場景: 在專案中有很多條數的資訊,且圖片很多的時候,不需要一次把整個頁面的圖片都載入完,而是在滾動到出現在螢幕才去載入該圖片的時候就可以用這個外掛。 二、簡單使用步驟: 1. 在專案裡面 npm

echo.js改造 實現可視區域圖片載入,lazyload效果

原來的echo.js有個缺點,快速滾動的時候不載入圖片,按住滾動條不放的時候圖片不載入,造成圖片空白不符合專案要求 改進程式碼如下: <script src="echo.min.js"></script> <script type="text

佔位圖和圖片載入專案實戰詳解

佔位圖(兜底圖): 真實圖片太大還沒有載入完之前先用一張佔位圖表示這個位置將來會有圖片或者說明這個位置是有圖片的但是不知道什麼原因真正的圖片沒有加載出來使用者只能看到這張佔位圖; 什麼是圖片懶載入: 懶載入也就是延遲載入,當訪問一個頁面的時候,先把img元素渲染出來,但是不給它真

vue 圖片載入 vue-lazyload

圖片懶載入 在實際的專案開發中,我們通常會遇見這樣的場景:一個頁面有很多圖片,而首屏出現的圖片大概就一兩張,那麼我們還要一次性把所有圖片都加載出來嗎?顯然這是愚蠢的,不僅影響頁面渲染速度,還浪費頻寬。這也就是們通常所說的首屏載入,技術上現實其中要用的技術就是圖片懶載入--到可視區域再載入。 vue中經常使

圖片載入的步驟

1、百度搜索v-lazy-npm 開啟首頁,然後在windows的cmd裡輸入npm install vue-lazyload --save (下載圖片懶載入的外掛) 2、複製下面程式碼到 main.js中 (注①:將有註釋刪掉的那句刪掉)(注②:粗體的那一句話、loading代表載入中的意

原生JS的(可視區域,向上滾動向下滾動兩種)圖片載入

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style>

基於Jquery的(可視區域,向上滾動向下滾動兩種)圖片載入

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style>

手機端圖片載入

圖片懶載入是手機內嵌h5開啟網頁速度的優化方式之一,今天我就接受如何用最少的程式碼解決手機端的圖片懶載入問題 因為公司使用的h5都是vue做的,但是其他框架使用方式是一樣的 當後臺資料相應後,一般我們會在html這麼操作 <div class="image" v-for="item in a

支援BetterScroll和iScroll滾動外掛的圖片載入的外掛

  做H5長頁面,內容都是一個個圖片。優化頁面速度,使用了圖片懶載入外掛。   下面我安利一款,我在網上尋找到這個懶載入外掛zhanyouwei/m-lazy,是支撐BetterScroll和iScroll滾動外掛的。 專案地址:https://github.com/zhanyou

圖片載入 滾動載入圖片載入)實現原理

滾動載入圖片(懶載入)實現原理   本文主要通過以下幾方面來說明懶載入技術的原理,個人前端小菜,有錯誤請多多指出 一、什麼是圖片滾動載入?   通俗的講就是:當訪問一個頁面的時候,先把img元素或是其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣就

layui圖片載入-loading佔位圖

前言     使用layui的圖片懶載入,發現未載入的圖片沒有loading佔位圖,顯示的是裂圖,看著不是很好。找了一些解決方法我統一記錄一下。 layui圖片懶載入使用方法 layui.use(’flow’, function(){ var flow = l

vue中使用圖片載入vue-lazyload外掛指南

使用方式 使用vue的 vue-lazyload 外掛 外掛地址: https://www.npmjs.com/package/vue-lazyload Installation 安裝方式 1. np

圖片載入 -- 爬蟲

圖片懶載入 什麼是圖片懶載入?   圖片懶載入是一種網頁優化技術。圖片作為一種網路資源,在被請求時也與普通靜態資源一樣,將佔用網路資源,而一次性將整個頁面的所有圖片載入完,將大大增加頁面的首屏載入時間。為了解決這種問題,通過前後端配合,使圖片僅在瀏覽器當前視窗內出現時才載入該圖片,達到減少首屏圖片請求數的

vue-lazyload 圖片載入

第一步npm install  vue-lazyload --save 然後在main.js裡引入 import VueLazyLoad from 'vue-lazyload' 然後使用這個VueLazyLoad Vue.use(VueLazyLoad,{ loadin

小程式圖片載入

Page({ data:{ // text:"這是一個頁面" hidden: false,

用angularjs指令寫一個圖片載入

思路: 先用一個比較小的img圖片提示使用者,正在載入圖片;等圖片載入完畢後,再顯示需要的圖片。 html:src為預設顯示的圖片,lazy-src為需要懶載入的圖片 <img image-lazy-load src="" lazy-src="..

vue-lazyload實現圖片載入的方式

1、安裝vue-lazyload npm install --save vue-lazyload 2、在main.js中引入並申明使用 (1)引入 import VueLazyload from 'vue-lazyload' (2)申明使用 Vue.use(Vue

圖片載入

html: <img src="/images/nullspecail.jpg" data-title="測試" data-src="http://kangsf1989.net/120-147-b.jpg"alt=""> js: <script>