一年多之前,為了能在老舊的 Vue 項目中開發 React 頁面,特地調研了一些主流的微前端框架:qiankun、無界等等。但都發現其實現的方案無法擺脱 JavaScript 的限制,不是 100%的將多個框架分離開,實施過程中,坑太多。於是採用了iframe這個天然的沙箱,將多個框架 100%分離開。從現在的角度來看,這個技術選型依然是正確的。接下來,詳細介紹一下iframe。
介紹
iframe 可以將另一個 HTML 頁面內嵌到當前頁面中,並且這兩個頁面是完全隔離的(沙箱隔離),不會存在 style 和 JavaScript 相互污染的情況。
- 這對於年久失修的項目來説,採用 iframe 方案,可以輕裝上陣,採用全新的技術棧進行項目開發,而不用考慮既有項目中冗餘複雜的邏輯。
- 一些富文本的顯示,需要避免樣式的污染;iframe 的天然沙箱特性,可以很好的滿足這一需求。
屬性
- width:iframe 的寬度,單位為像素。
- height:iframe 的寬度,單位為像素。
-
loading:指示瀏覽器什麼時候加載 iframe 的內容。
- eager:默認值;只要 iframe 出現在 DOM 中,就立即加載。
- lazy:當 iframe 將要出現在視口範圍附近時(具體距離由瀏覽器決定),就加載 iframe。
-
src:iframe 加載頁面的 URL。
- 如果不設置 src,則表示
about:blank,一個與父頁面同源的空白頁面。
- 如果不設置 src,則表示
- srcdoc:一段 HTML 字符串,內嵌到 iframe 的 body 裏;如果存在 srcdoc,則會覆蓋 src。
iframe 初始化
為了讓 iframe 更好地融合到當前頁面,表現的像一個普通的 DOM 元素,而非單獨的頁面。為此,需要對 iframe 進行樣式的初始化。
<iframe style="width: 100%; border: none;" />
同一站點,共用一個渲染進程、一個主線程
為了節省系統資源,瀏覽器會將同一個站點(協議、一級域名、端口都相同)的 iframe 頁面放在同一個渲染進程裏,不同站點的頁面放到不同的渲染進程裏。
先看一個具體的例子,假設該頁面的 URL 為https://www.baidu.com/main:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>test iframe</title>
</head>
<body>
<iframe srcdoc="<h1>2342</h1>"></iframe>
<iframe
src="https://www.baidu.com/s?wd=%E4%B8%A4%E9%83%A8%E9%97%A8%E5%B0%86%E5%90%91%E5%9B%B0%E9%9A%BE%E7%BE%A4%E4%BC%97%E5%8F%91%E6%94%BE%E4%B8%80%E6%AC%A1%E6%80%A7%E8%A1%A5%E5%8A%A9&sa=fyb_n_homepage&rsv_dl=fyb_n_homepage&from=super&cl=3&tn=baidutop10&fr=top1000&rsv_idx=2&hisfilter=1"
></iframe>
<iframe
src="https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_8706013891227417784%22%7D&n_type=-1&p_from=-1"
></iframe>
<iframe src="https://www.zybang.com/"></iframe>
<iframe src="https://zyb.zuoyebang.com/"></iframe>
<iframe src="https://jiazhang.zuoyebang.com/"></iframe>
<iframe src="https://zuoyebang.vip/"></iframe>
</body>
</html>
通過 HTML 代碼和瀏覽器的任務管理器,可以看到:一共 8 個頁面,但只創建了 4 個渲染進程。
- baidu.com 渲染進程:
www.baidu.com/main、srcdoc="<h1>2342</h1>"、www.baidu.com/s、mbd.baidu.com - zuoyebang.vip 渲染進程:
zuoyebang.vip - zuoyebang.com 渲染進程:
zyb.zuoyebang.com、jiazhang.zuoyebang.com - zybang.com 渲染進程:
www.zybang.com
iframe 使用渲染進程數目的流程圖,如下:
缺點
多個頁面共用一個主線程,帶來的問題是:如果某個頁面的任務長期佔據主線程,那麼其他頁面的主線程任務將無法得到執行。
例如:父頁面有一個打印時間的定時器任務;子頁面有個死循環;當子頁面加載後,由於佔據了主線程,導致父頁面的定時器任務無法執行;由於頁面的滑動不涉及主線程,所以頁面的滑動非常順暢。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>child</title>
</head>
<body>
<script>
while (true) {}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>parent</title>
</head>
<body>
<div style="height: 5000px;"></div>
<iframe src="http://127.0.0.1:8080/child.html" loading="lazy"></iframe>
<script>
setInterval(() => {
console.log(new Date())
}, 1000)
</script>
</body>
</html>
https://www.bilibili.com/video/BV1QGsfeKEAo/?aid=113208006283...
總結
iframe,沙箱特性,天然地將兩個頁面隔離開。還可以與同一站點公用一個渲染進程,節省系統資源的消耗。目前看,iframe是微前端的最佳選擇。