js前端圖片加載異常兜底方案_第1頁
js前端圖片加載異常兜底方案_第2頁
js前端圖片加載異常兜底方案_第3頁
js前端圖片加載異常兜底方案_第4頁
js前端圖片加載異常兜底方案_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第js前端圖片加載異常兜底方案網(wǎng)絡(luò)環(huán)境總是多樣且復(fù)雜的,一張圖片可能會因為網(wǎng)路狀況差而加載失敗或加載超長時間,也可能因為權(quán)限不足或者資源不存在而加載失敗,這些都會導(dǎo)致用戶體驗變差,所以我們需要一個圖片加載異常的兜底方案。

img加載錯誤解決方案

直接在img標(biāo)簽上使用內(nèi)聯(lián)事件處理圖片加載失敗的情況,但是這種方式代碼侵入性太大,指不定就會有地方漏掉。

imgsrc=xxxxxonerror=this.src=default.png

全局img添加事件

第一個方案侵入性太大,我們將入口收斂,為所有img標(biāo)簽統(tǒng)一添加error處理事件。

constimgs=document.getElementsByTagName(img)

Atotype.forEach.call(imgs,img={

img.addEventListener(error,e={

e.target.src=default.png

利用error事件捕獲

為每個img添加事件處理函數(shù)的代價還是高了點,我們知道一般事件會經(jīng)歷三個階段:

捕獲階段

處于目標(biāo)階段

冒泡階段

根據(jù)MDN文檔中的描述:

Whenaresource(suchasanimgorscript)failstoload,anerroreventusinginterfaceEventisfiredattheelementthatinitiatedtheload,andtheonerror()handlerontheelementisinvoked.Theseerroreventsdonotbubbleuptowindow,butcanbehandledwithaEventTarget.addEventListenerconfiguredwithuseCapturesettotrue.

我們可以知道img和srcipt標(biāo)簽的error并不會冒泡,但是會經(jīng)歷捕獲階段和處于目標(biāo)階段。前兩個方案就是利用處于目標(biāo)階段觸發(fā)事件函數(shù),這一次我們在捕獲階段截獲并觸發(fā)函數(shù),從而減少性能損耗。

document.addEventListener(

error,

e={

lettarget=e.target

consttagName=target.tagName||

if(tagName.toLowerCase=img){

target.src=default.png

target=null

true

替換src方式的最優(yōu)解

上面的方案有兩個缺點:

如果是因為網(wǎng)絡(luò)差導(dǎo)致加載失敗,那么加載默認(rèn)圖片的時候也極大概率會失敗,于是會陷入無限循環(huán)。

如果是網(wǎng)絡(luò)波動導(dǎo)致的加載失敗,那么圖片可能重試就會加載成功。

所以我們可以為每個img標(biāo)簽額外添加一個data-retry-times計數(shù)屬性,當(dāng)重試超過限制次數(shù)后就用base64圖片作為默認(rèn)兜底。

document.addEventListener(

error,

e={

lettarget=e.target

consttagName=target.tagName||

constcurTimes=Number(target.dataset.retryTimes)||0

if(tagName.toLowerCase()===img){

if(curTimes=3){

target.src=data:image/png;base64,xxxxxx

}else{

target.dataset.retryTimes=curTimes+1

target.src=target.src

target=null

true

CSS處理的最優(yōu)解

上面方式是采用替換src的方式來展示兜底圖,這種解決方式有一個缺陷:

原圖的資源鏈接無法從標(biāo)簽上獲?。m然可以通過加data-xxx屬性的方式hack解決)。

所以還有一種更好的方式,就是利用CSS偽元素::before和::after覆蓋原本元素,直接展示兜底base64圖片。

CSS樣式如下:

img.error{

display:inline-block;

transform:scale(1);

content:

color:transparent;

img.error::before{

content:

position:absolute;

left:0;top:0;

width:100%;height:100%;

background:#f5f5f5url(data:image/png;base64,xxxxxx)no-repeatcenter/50%50%;

img.error::after{

content:attr(alt);

position:absolute;

left:0;bottom:0;

width:100%;

line-height:2;

background-color:rgba(0,0,0,.5);

color:white;

font-size:12px;

text-align:center;

white-space:nowrap;

overflow:hidden;

text-overflow:ellipsis;

JS代碼如下:

document.addEventListener(

error,

e={

lettarget=e.target

consttagName=target.tagName||

constcurTimes=Number(target.dataset.retryTimes)||0

if(tagName.toLowerCase()===img){

if(curTimes=3){

target.classList.remove(error)

target.classList.add(error)

}else{

target.dataset.retryTimes=curTimes+1

target.src=target.src

target=null

true

img加載超時解決方案

目前大多數(shù)應(yīng)用都會接入CDN來加速資源請求,但是CDN存在節(jié)點覆蓋不全的問題,導(dǎo)致DNS查詢超時,此時如果切換Domain可能就會加載成功。

嗅探切換Domain(CNAME)

我們可以使用嗅探的方式,測試CDN提供的Domain是否能夠正常訪問,如果不行或者超時就及時切換成可訪問Domain。其中有幾個注意點:

為了防止嗅探圖片緩存,需要添加時間戳保持新鮮度

Image圖片加載沒有超時機制,使用setTimeout模擬超時

//防止嗅探圖片存在緩存,添加時間戳保持新鮮度

exportconstimgUri=`/img/xxxxxtimestamp=${Date.now()}${Math.random()}`;

exportconstoriginDomain=

//可采用配置下發(fā)的方式

exportconstcdnDomains=[

,

,

,

exportconstvalidateImageUrl=(url:string)={

returnnewPromisestring((resolve,reject)={

constimg=newImage();

img.onload=()={

resolve(url);

img.onerror=(e:string|Event)={

reject(e);

//promise的狀態(tài)不可變性,使用setTimeout模擬超時

consttimer=setTimeout(()={

clearTimeout(timer);

reject(newError(ImageLoadTimeout

},10000);

img.src=url;

exportconstsetCDNDomain=()={

constcdnLoop=()={

returnPromise.race(

cdnDomains.map((domain:string)=validateImageUrl(domain+imgUri)),

).then(url={

window.shouldReplaceDomain=true;

consturlHost=url.split(/)[2];

window.replaceDomain=urlHost;

returnvalidateImageUrl(`${originDomain}${imgUri}`)

.then(()={

window.shouldReplaceDomain=false;

window.replaceDomain=

.catch(()={

returncdnLoop();

//替換URL

exportconstreplaceImgDomain=(src:string)={

if(srcwindow.shouldReplaceDomainwindow.replaceDomain){

returnsrc.replace(originDomain.split(/)[2],window.replaceDomain);

returnsrc;

服務(wù)端下發(fā)Domain(CNAME)

該方案需要后臺同學(xué)配合,由后臺判斷當(dāng)前當(dāng)前可用Domain并返回。

getUsefulDomain()

.then(e={

window.imgDomain=e.data.imgDomain||

background-image加載異常解決方案

實際應(yīng)用中背景圖也會加載失敗,通常這些元素沒有error事件,所以也就無從捕獲error事件了。此時就可以利用dispatchEvent,它同樣擁有捕獲階段,MDN文檔上是這么介紹的:

DispatchesanEventatthespecifiedEventTarget,(synchronously)invokingtheaffectedEventListenersintheappropriateorder.Thenormaleventprocessingrules(includingthecapturingandoptionalbubblingphase)alsoapplytoeventsdispatchedmanuallywithdispatchEvent().

可以看到支持度也還是可以的,我們首先需要自定義一個事件并初始化這個事件,在背景圖加載失敗的時候觸發(fā)這個自定義事件,最后在上層捕獲這個事件并執(zhí)行事件函數(shù)。

自定義事件

自定義事件有兩種方式:

使用createEvent()和initEvent(),但是根據(jù)MDN文檔,initEvent方法已經(jīng)從瀏覽器標(biāo)準(zhǔn)中移除,并不安全,但支持度很高。

使用newEvent()的方式,但是支持率稍微差一點

這里以第二種為例,根據(jù)MDN文檔的用法創(chuàng)建一個自定義事件:

constevent=newEvent(bgImgError)

嗅探加載情況

使用前面定義的方法嗅探圖片資源的情況。

validateImageUrl(xxx.png)

.catch(e={

letele=document.getE

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論