文章出處

  在我上篇文章里,我提到一種使用iframe完成無阻塞腳本加載的方式,因為我對iframe的偏見很大,所以上篇文章里我沒有展開討論這個問題。

  文章發表后有位網友問了我這樣一個問題,下面是他問題的原文,如下所示:

 

我一個電商后臺系統,用的表格控件是flexigrid,,里面是個iframe來的,每一個tab就是一個iframe,現在遇到的問題就是,如果其中一個或者多個iframe在加載數據,還沒加載完,如果這個時候,我再去開一個tab,也是查找數據,可能數據量很大,或者提交數據(其他的iframe可能還在加載數據),這個時候很容易出現瀏覽器卡死,一直轉圈的現象,這個跟你說的這個js阻塞也有關系吧。跟這個js單線程的特性,線程阻塞有多大的關系~~

  

 

  這個現象很有趣,就和我在上篇文章里談到我思考無阻塞腳本加載的源起一樣,研究這個朋友提供的現象應該也能給我們很大的收獲。

  首先,這位朋友提到“如果其中一個或者多個iframe在加載數據,還沒加載完,如果這個時候,我再去開一個tab,也是查找數據,可能數據量很大,或者提交數據(其他的iframe可能還在加載數據),這個時候很容易出現瀏覽器卡死,一直轉圈的現象”,這個現象讓我有個疑問:

  首先我們要明確頁面使用iframe時候等于一個頁面里嵌套一個頁面,iframe的src指向的頁面其實和父頁面是相對獨立的,那么一個帶了iframe的頁面,父頁面的加載過程和iframe加載的過程是怎樣的關系了,具體點就是父頁面是不是要等待iframe頁面里所有資源加載完畢后才會觸發onload事件,頁面的onload事件觸發了,也就代表頁面的忙指示結束,而忙指示是我們衡量頁面是否被阻塞的一個重要標志。

  幸運的是有人已經幫我們做了這個實驗,下面我來描述下這個實驗的方式:

  阻塞加載方式即在頁面直接寫:

<iframe src=”url”></iframe>

  

  Iframe的url指向的頁面分為四種類型:

  1.url指向一個空文檔,空文檔不是指頁面指向的網頁不存在,而是指向網頁里只有最基本的html,例如:

<html><head></head><body><p>ddddd</p></body></html>

  

     這時候iframe加載就不會因為內部靜態資源而被阻塞。

  2.url指向的頁面里包含圖片;

  3.url指向的頁面包含外部腳本;

  4.url指向的頁面包含外部css樣式文件。

  上面的靜態資源,實驗設計者都讓它們的加載有延時,實驗的結果是令人失望的,這些靜態資源加載都會阻塞父頁面的加載,即iframe的加載延長了忙指示結束的時間。

  接下來實驗者又做了一個實驗,這個時候在父頁面里iframe的src設為空,然后使用javascript代碼給iframe設定src的值,賦值的時機也是在onload事件之前,而url指向和上個實驗一致,結果是在以webkit為內核的safari和chrome下,頁面加載明顯變快,iframe的加載沒有阻塞父頁面的加載,但是在其他瀏覽器下這個結果是令人失望的,阻塞任然存在,甚至比以前還要嚴重。

  Iframe的加載是能阻塞父頁面的加載,上面朋友的現象描述里:一個iframe沒有加載完畢,用戶可能就會選擇另外一個iframe,另一個iframe也在加載新頁面,這個描述說明了,這個朋友的iframe的src應該都是使用javascript設置,而不是事先填好的,他的場景符合實驗二的情況。這里又會產生一個問題,第一個iframe可能是和主頁面資源加載同步的,即主頁面很有可能還沒觸發onload事件,為啥用戶還能觸發iframe的加載操作,按我原來的邏輯,這時候頁面應該是不能接收任何響應的,這里我要糾正下這個觀點,頁面被阻塞不代表頁面會停止接收用戶的所做的相關操作,例如在ie瀏覽器,如果頁面被阻塞,用戶點擊了兩次按鈕,瀏覽器會認為用戶的操作是有效的,會將用戶的操作加入到瀏覽器執行的UI線程里的,這是瀏覽器對于性能不佳網頁的一個妥協做法。

  Iframe阻塞頁面加載的問題還有更多深層次的原因,首先iframe頁面dom元素中加載最慢的,大家可以看看下面這張圖:

 

  我們使用dom在頁面里創建iframe、a、div、srcipt和style節點,第一欄是創建10個節點,第二欄是創建100個節點,第三欄是創建1000個節點,數值是代表創建的時間,由此可見創建iframe越多,耗時越長,可見iframe本身就是頁面性能的瓶頸所在。

  在前面文章里我講到網站為了提升頁面資源并行下載的,可以將通用的靜態資源放到一個獨立的域名下,跨域可以增加頁面連接數,使用iframe的頁面會有兩個url,iframe能達到增加并行下載的目的嗎?如果iframe的url和父頁面的url不同,能不能增加我沒有做過測試,無法回答,但是針對這個朋友的問題,他使用的iframe的url肯定會和父頁面在同一個域下面,因為他使用的iframe目的是為了布局而不是為了嵌入其他web的頁面,iframe和父頁面同域的結果就是并發連接數是不能被增加的,因為iframe是指向一個完整的頁面,在加上上面說的iframe其實也會阻塞頁面的加載,因此這個場景下就等于瀏覽器同時加載兩個獨立頁面卻要遵守一個頁面加載的方案,結果自然是頁面會變得更慢。

  由于這個朋友的應用是內部的控制臺,因此它的網站絕對不會有做那些提升網站性能的優化工作,網站優化里有一條就是:將外部的css文件和js文件緩存,所以這個朋友網站肯定會出現這個問題,第一個iframe還沒加載完,用戶打開了第二個iframe,這兩個iframe使用的外部css文件和js文件可能大部分相同,但是它們在每個iframe里都會被重新加載,而且第一個iframe沒有加載完畢,還會阻塞第二個iframe對靜態資源的加載,如果開啟的iframe越多,阻塞就越加嚴重,后果自然也是網站越來越慢。

  那么我們該怎么幫這個朋友解決他的問題了?最好的方式就是將iframe去掉,使用div來實現選項卡,這么做太殘酷,要重構整個前端代碼,這個朋友問我的目的就是不想這么干了。

  所以要考慮下代價較少的方法,下面是我晚上想到的,希望看了我博客的大牛們也會有更多更好的建議,我想到的如下:

  1. 這個網站的性能問題源自于iframe使用過多,那么我們應該減少iframe,所以這個朋友可以將頁面主頁面的布局改為傳統布局,即菜單放到頁面左邊,頁面上去掉選項卡,工作區只有一個iframe,這樣就只需要修改主頁面就行了。不過這樣會減少一個用戶友好的功能,這個朋友使用選項卡好處就是iframe能有記憶功能,但是左邊菜單一個iframe后沒點一次菜單就得重新打開頁面,不過失去這個功能和性能損失比起來我相信還是性能更加重要。
  2. 將頁面的靜態資源添加緩存功能,緩存外部的js文件、css文件還有圖片,我不知道這個朋友服務端使用什么語言開發,如果是java的話,生產的web容器應該是tomcat,jboss之流了,這些java的web容器怎么設置靜態資源緩存我還真的不清楚,最好還是將靜態資源放到apache,ngnix這樣的web服務器下,如果使用靜態資源服務器最好提供一個和主服務器的域名不一樣的訪問地址,這樣還可以提升瀏覽器并發下載的連接數。

  文章寫畢,最后再重申一下希望有大牛看了本人的文章,能告訴我們更多更好的方式。

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()