在我上篇文章里,我提到一種使用iframe完成無阻塞腳本加載的方式,因為我對iframe的偏見很大,所以上篇文章里我沒有展開討論這個問題。
文章發(fā)表后有位網(wǎng)友問了我這樣一個問題,下面是他問題的原文,如下所示:
1 | 我一個電商后臺系統(tǒng),用的表格控件是flexigrid,,里面是個iframe來的,每一個tab就是一個iframe,現(xiàn)在遇到的問題就是,如果其中一個或者多個iframe在加載數(shù)據(jù),還沒加載完,如果這個時候,我再去開一個tab,也是查找數(shù)據(jù),可能數(shù)據(jù)量很大,或者提交數(shù)據(jù)(其他的iframe可能還在加載數(shù)據(jù)),這個時候很容易出現(xiàn)瀏覽器卡死,一直轉(zhuǎn)圈的現(xiàn)象,這個跟你說的這個js阻塞也有關(guān)系吧。跟這個js單線程的特性,線程阻塞有多大的關(guān)系~~ |
這個現(xiàn)象很有趣,就和我在上篇文章里談到我思考無阻塞腳本加載的源起一樣,研究這個朋友提供的現(xiàn)象應(yīng)該也能給我們很大的收獲。
首先,這位朋友提到“如果其中一個或者多個iframe在加載數(shù)據(jù),還沒加載完,如果這個時候,我再去開一個tab,也是查找數(shù)據(jù),可能數(shù)據(jù)量很大,或者提交數(shù)據(jù)(其他的iframe可能還在加載數(shù)據(jù)),這個時候很容易出現(xiàn)瀏覽器卡死,一直轉(zhuǎn)圈的現(xiàn)象”,這個現(xiàn)象讓我有個疑問:
首先我們要明確頁面使用iframe時候等于一個頁面里嵌套一個頁面,iframe的src指向的頁面其實和父頁面是相對獨立的,那么一個帶了iframe的頁面,父頁面的加載過程和iframe加載的過程是怎樣的關(guān)系了,具體點就是父頁面是不是要等待iframe頁面里所有資源加載完畢后才會觸發(fā)onload事件,頁面的onload事件觸發(fā)了,也就代表頁面的忙指示結(jié)束,而忙指示是我們衡量頁面是否被阻塞的一個重要標(biāo)志。
幸運的是有人已經(jīng)幫我們做了這個實驗,下面我來描述下這個實驗的方式:
阻塞加載方式即在頁面直接寫:
1 | < iframe src=”url”></ iframe > |
Iframe的url指向的頁面分為四種類型:
1.url指向一個空文檔,空文檔不是指頁面指向的網(wǎng)頁不存在,而是指向網(wǎng)頁里只有最基本的html,例如:
1 | < html >< head ></ head >< body >< p >ddddd</ p ></ body ></ html > |
這時候iframe加載就不會因為內(nèi)部靜態(tài)資源而被阻塞。
2.url指向的頁面里包含圖片;
3.url指向的頁面包含外部腳本;
4.url指向的頁面包含外部css樣式文件。
上面的靜態(tài)資源,實驗設(shè)計者都讓它們的加載有延時,實驗的結(jié)果是令人失望的,這些靜態(tài)資源加載都會阻塞父頁面的加載,即iframe的加載延長了忙指示結(jié)束的時間。
接下來實驗者又做了一個實驗,這個時候在父頁面里iframe的src設(shè)為空,然后使用javascript代碼給iframe設(shè)定src的值,賦值的時機(jī)也是在onload事件之前,而url指向和上個實驗一致,結(jié)果是在以webkit為內(nèi)核的safari和chrome下,頁面加載明顯變快,iframe的加載沒有阻塞父頁面的加載,但是在其他瀏覽器下這個結(jié)果是令人失望的,阻塞任然存在,甚至比以前還要嚴(yán)重。
Iframe的加載是能阻塞父頁面的加載,上面朋友的現(xiàn)象描述里:一個iframe沒有加載完畢,用戶可能就會選擇另外一個iframe,另一個iframe也在加載新頁面,這個描述說明了,這個朋友的iframe的src應(yīng)該都是使用javascript設(shè)置,而不是事先填好的,他的場景符合實驗二的情況。這里又會產(chǎn)生一個問題,第一個iframe可能是和主頁面資源加載同步的,即主頁面很有可能還沒觸發(fā)onload事件,為啥用戶還能觸發(fā)iframe的加載操作,按我原來的邏輯,這時候頁面應(yīng)該是不能接收任何響應(yīng)的,這里我要糾正下這個觀點,頁面被阻塞不代表頁面會停止接收用戶的所做的相關(guān)操作,例如在ie瀏覽器,如果頁面被阻塞,用戶點擊了兩次按鈕,瀏覽器會認(rèn)為用戶的操作是有效的,會將用戶的操作加入到瀏覽器執(zhí)行的UI線程里的,這是瀏覽器對于性能不佳網(wǎng)頁的一個妥協(xié)做法。
Iframe阻塞頁面加載的問題還有更多深層次的原因,首先iframe頁面dom元素中加載最慢的,大家可以看看下面這張圖:
我們使用dom在頁面里創(chuàng)建iframe、a、div、srcipt和style節(jié)點,第一欄是創(chuàng)建10個節(jié)點,第二欄是創(chuàng)建100個節(jié)點,第三欄是創(chuàng)建1000個節(jié)點,數(shù)值是代表創(chuàng)建的時間,由此可見創(chuàng)建iframe越多,耗時越長,可見iframe本身就是頁面性能的瓶頸所在。
在前面文章里我講到網(wǎng)站為了提升頁面資源并行下載的,可以將通用的靜態(tài)資源放到一個獨立的域名下,跨域可以增加頁面連接數(shù),使用iframe的頁面會有兩個url,iframe能達(dá)到增加并行下載的目的嗎?如果iframe的url和父頁面的url不同,能不能增加我沒有做過測試,無法回答,但是針對這個朋友的問題,他使用的iframe的url肯定會和父頁面在同一個域下面,因為他使用的iframe目的是為了布局而不是為了嵌入其他web的頁面,iframe和父頁面同域的結(jié)果就是并發(fā)連接數(shù)是不能被增加的,因為iframe是指向一個完整的頁面,在加上上面說的iframe其實也會阻塞頁面的加載,因此這個場景下就等于瀏覽器同時加載兩個獨立頁面卻要遵守一個頁面加載的方案,結(jié)果自然是頁面會變得更慢。
由于這個朋友的應(yīng)用是內(nèi)部的控制臺,因此它的網(wǎng)站絕對不會有做那些提升網(wǎng)站性能的優(yōu)化工作,網(wǎng)站優(yōu)化里有一條就是:將外部的css文件和js文件緩存,所以這個朋友網(wǎng)站肯定會出現(xiàn)這個問題,第一個iframe還沒加載完,用戶打開了第二個iframe,這兩個iframe使用的外部css文件和js文件可能大部分相同,但是它們在每個iframe里都會被重新加載,而且第一個iframe沒有加載完畢,還會阻塞第二個iframe對靜態(tài)資源的加載,如果開啟的iframe越多,阻塞就越加嚴(yán)重,后果自然也是網(wǎng)站越來越慢。
那么我們該怎么幫這個朋友解決他的問題了?最好的方式就是將iframe去掉,使用div來實現(xiàn)選項卡,這么做太殘酷,要重構(gòu)整個前端代碼,這個朋友問我的目的就是不想這么干了。
所以要考慮下代價較少的方法,下面是我晚上想到的,希望看了我博客的大牛們也會有更多更好的建議,我想到的如下:
文章寫畢,最后再重申一下希望有大牛看了本人的文章,能告訴我們更多更好的方式。