前端 ajax 加載緩存方案 —— 圖片強制緩存

前端 ajax 加載緩存方案 —— 圖片強制緩存

前言

上一篇 寫了關於前端如何緩存 ajax 加載的數據,如果對這個話題感興趣又沒有看過的童鞋,不妨前去一觀:https://blog.csdn.net/lovefengruoqing/article/details/103780958

這一篇文章是上一篇文章的後續,所以,如果沒看過上一篇文章的話,有些內容可能理解起來,還是有點障礙的,因爲有些前置的內容,這篇文章不會細講,而是會直奔主題。

很多時候,瀏覽器會強制對頁面裏面的靜態資源進行緩存,以提升頁面的二次加載速度。

當然這種說法,其實是不太準確的,因爲我們是可以通過多種方式來控制這種“瀏覽器默認的緩存機制”。

既可以通過在 html 的 head 中加標籤來控制,也可以通過在後端響應前端的請求的響應頭中設置參數來控制。

如果想詳細研究的話,請參考 stackoverflow 上的相關討論,已經很詳細了:https://stackoverflow.com/questions/49547/how-do-we-control-web-page-caching-across-all-browsers

這種瀏覽器默認的緩存的機制,其實是不可靠的,因爲對於我們來說,不是完全可控的。

如果我們想要一種完全可控的前端圖片緩存機制,我們該如何做呢?

彆着急,耐心往下看,你就明白應該怎麼處理了。

前端默認加載圖片的幾種方式

我們知道的是,默認情況下,我們加載圖片,都是藉助 html 標籤來加載的,我們一般的做法有幾種:

1. html 方式

直接寫在 html 代碼中,將 img 標籤的 src 設置爲我們圖片的路徑。

<img src="https://www.baidu.com/img/bd_logo1.png">

2. JavaScript 方式

通過創建一個 Image 對象的實例,然後將該實例的 src 屬性設置爲我們圖片的路徑。

var img = new Image();
img.src = 'https://www.baidu.com/img/bd_logo1.png';
img.onload = () => {
	console.log('圖片加載完成✅!');
}

上面 👆 這兩種方式,都不是我們可控的。

因爲這兩種方式,有個共同點,都不是通過 ajax 方式加載的,而是瀏覽器引擎解析了以後,自動請求的。

打開 devtools,你就會明白這種說法是什麼意思。

image.png

但是如果,我們將圖片的加載完全改成 ajax 加載,那麼我們就可以完全控制,是否需要對圖片做緩存了。

但是如何做呢?

緩存用我們上一篇文章的中的 IndexedDB 就可以實現,但是我們如何 🤔️ 通過 ajax 的方式,來加載圖片呢?

如果你沒嘗試過,那麼接下來,我會提供幾種可行的方案。

當然,fetch 會遇到

ajax 加載圖片

這裏我們藉助 fetch 這個 api,來方便我們發送 ajax 請求。

fetch(imgUrl);

然後我們可以通過 then,拿到請求到的對象,但是這個對象需要封裝成文件,我們才能使用。

fetch(imgUrl)
  .then(response => response.blob());

1. URL.createObjectURL

然後再通過 then 的鏈式調用,拿到封裝後的文件對象。

在這種方式,我們通過 URL.createObjectURL 這個 api,對拿到的文件對象進行封裝,封裝了以後,會返回一個新的 url 對象,這個對象可以理解爲我們瀏覽器中的該對象的引用或者指針,就是指代該對象的。

如果不瞭解 URL.createObjectURL,可以參考下該頁面:https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL

fetch(imgUrl)
  .then(response => response.blob())
  .then(blob => {
    var imgUrl = URL.createObjectURL(blob);
    callback(imgUrl);
  });

如果不理解爲什麼要這麼用,可以參考下面這個在 input 選擇圖片上傳的過程中預覽圖片的小 demo:https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications#Example_Using_object_URLs_to_display_images

2. base64 格式

base64 也是一種常見用來存儲圖片的格式,我們可以藉助其將圖片編碼爲字符串,便於我們存儲在數據庫或者代碼之中。

我們當然也可以藉助 base64 的方式,來存儲我們通過 ajax 方式請求到的圖片。

我們直接將獲取到的 blob 文件,通過 FileReader 對象上的 readAsDataURL 這個 api,將其讀取成 base64 格式的圖片。

fetch(imgUrl)
  .then(response => response.blob())
  .then(blob => {
    const fileReader = new FileReader();
    fileReader.onload = (e) => {
      var base64 = e.target.result;
      console.log(base64);
    };
    // readAsDataURL
    fileReader.readAsDataURL(blob);
    fileReader.onerror = () => {
      console.error(new Error('blobToBase64 error'));
    };
  });

理清楚了這個思路以後,接下來,就可以接着上一篇文章的思路來了。

我們直接將 blob 存儲在 IndexedDB 數據庫中,我們藉助 read 從 imagePool 這個表中讀取我們請求的 url,當讀取成功了,就證明這個文件我們曾經讀取過,屬於二次加載。

那麼我們 then 的 resolve 方法中就會被調用,否則 reject 方法就會被調用。

const resolve = (data) => {
  callback(URL.createObjectURL(data));
}

const reject = () => fetch(url)
  .then(response => response.blob())
  .then(blob => {
    add(blob, url, 'imagePool');
    var imgUrl = URL.createObjectURL(blob);
    callback(imgUrl);
  });

function getImageByXHR(url, callback) {
  read(url, 'imagePool')
    .then(
      reslove,
      reject
    )
    .catch(function(err) {
      console.log(err);
    });
}

當然,就像我們之前講過的那樣,凡事都有利弊,需要合理的衡量利弊。

在性能和內存佔用以及兼容性之間,找到一個合適的平衡點,足以。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章