<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      記錄---一篇文了解qiankun的代碼隔離原理

      ????? 寫在開頭

      點贊 + 收藏 === 學會??????

      隨著前端業務的快速發展,微前端架構已經被廣泛采用,其中 qiankun 作為主流解決方案也越來越受到關注。前幾天面試時,我就被問到了一個高頻問題:qiankun 是如何實現 JS 和 CSS 隔離的?

      qiankun 的JS 沙箱

      qiankun 的微前端場景是:主應用加載多個子應用,不同子應用可能依賴不同版本的庫、全局變量,甚至可能會互相覆蓋 window 上的屬性。為了避免“全局污染”,qiankun 提供了沙箱機制。

      常見的JS 沙箱實現思路有下面三種:

      SnapshotSandbox(快照沙箱)

      快照沙箱是微前端里最直觀的 JS 隔離方式之一:

      • 掛載應用前 → 對 window 對象做一次“快照”,保存所有屬性及其值。
      • 應用運行中 → 子應用可以隨意修改全局變量。
      • 卸載應用時 → 把 window 恢復到掛載前的快照狀態(新增的刪掉、改過的還原)。

      它的過程使用偽代碼大致如下:

      /**
       * 快照沙箱
       * - 掛載前:拍快照(淺拷貝 window 屬性)
       * - 卸載時:恢復快照(刪除新增,還原修改)
       */
      function createSnapshotSandbox() {
        const rawWindow = window;
        let snapshot = null;      // 存儲拍下來的全局狀態
        let modifiedProps = {};   // 存儲運行過程中被修改的屬性
      
        return {
          // 激活:拍下當前 window 狀態
          activate() {
            snapshot = {};
            for (const key in rawWindow) {
              try {
                snapshot[key] = rawWindow[key];
              } catch (_) {
                // 某些屬性可能不可訪問,忽略即可
              }
            }
          },
      
          // 記錄全局修改(手動寫變量時調用)
          set(key, value) {
            modifiedProps[key] = rawWindow[key];
            rawWindow[key] = value;
          },
      
          // 失活:恢復 window 到快照
          deactivate() {
            for (const key in rawWindow) {
              if (!(key in snapshot)) {
                // 卸載后刪除新增的
                delete rawWindow[key];
              } else if (rawWindow[key] !== snapshot[key]) {
                // 還原被修改的
                rawWindow[key] = snapshot[key];
              }
            }
            modifiedProps = {};
          }
        };
      }

      上述代碼中,snapshot 是全局變量的“拍照備份”,在 sandbox.activate() 時,會遍歷一次 window,保存所有當前的屬性和值。它用于記錄掛載子應用之前的 window 狀態,在卸載時(deactivate)時,拿這個備份和當前 window 對比,使 window 回到快照時的狀態。

      • 刪除新增屬性(子應用新增的全局變量)。
      • 還原被修改的屬性(子應用修改過的變量)。

      modifiedProps 是運行時的“變更記錄”,使用它快速知道子應用改動了哪些屬性,卸載時可以更高效地只恢復被改動過的,而不是全量比對。

      使用示例:

      const sandbox = createSnapshotSandbox();
      
      sandbox.activate();  // 掛載前,拍快照
      window.foo = 123;    // 模擬子應用寫全局
      console.log(window.foo); // 123
      
      sandbox.deactivate(); // 卸載后恢復
      console.log(window.foo); // undefined(被刪除)

      LegacySandbox(單實例沙箱)

      快照沙箱 (SnapshotSandbox) 雖然能恢復全局變量,但性能差,還不支持并行運行。
      因此 qiankun 在 支持 Proxy 之前,實現了一個改進版的沙箱 —— LegacySandbox

      簡化版代碼示例:

      class LegacySandbox {
        constructor(name) {
          this.name = name;
      
          this.addedPropsMap = new Map();              // 記錄新增的全局屬性
          this.modifiedPropsOriginalMap = new Map();   // 記錄修改前的原始值
          this.currentUpdatedPropsValueMap = new Map();// 記錄當前子應用改動后的值
        }
      
        // 激活:恢復上次的運行環境
        activate() {
          this.currentUpdatedPropsValueMap.forEach((v, p) => {
            window[p] = v;
          });
        }
      
        // 失活:清理全局變量
        deactivate() {
          // 刪除新增屬性
          this.addedPropsMap.forEach((_, p) => {
            delete window[p];
          });
          // 恢復修改過的屬性
          this.modifiedPropsOriginalMap.forEach((v, p) => {
            window[p] = v;
          });
        }
      
        // 設置全局變量時調用
        setWindowProp(prop, value) {
          if (!window.hasOwnProperty(prop)) {
            // 新增屬性
            this.addedPropsMap.set(prop, value);
          } else if (!this.modifiedPropsOriginalMap.has(prop)) {
            // 第一次修改,記錄原始值
            this.modifiedPropsOriginalMap.set(prop, window[prop]);
          }
          // 記錄最新值
          this.currentUpdatedPropsValueMap.set(prop, value);
          window[prop] = value;
        }
      }

      LegacySandbox 的核心思路是:

      • 維護三份狀態: addedPropsMap:記錄子應用新增的全局屬性。modifiedPropsOriginalMap:記錄子應用修改前的原始值。currentUpdatedPropsValueMap:記錄子應用修改后的值。
      • 激活(activate): 遍歷 currentUpdatedPropsValueMap,恢復上次運行時的修改。
      • 運行中: 每當子應用往 window 上賦值時:如果是新增 → 記錄到 addedPropsMap。如果是修改 → 記錄原始值到 modifiedPropsOriginalMap,并把新值寫到 currentUpdatedPropsValueMap
      • 失活(deactivate): 刪除 addedPropsMap 中的屬性(還原新增)。用 modifiedPropsOriginalMap 恢復被修改過的屬性(還原修改)。

      使用示例:

      const sandbox = new LegacySandbox("app1");
      
      sandbox.activate();              // 激活應用
      sandbox.setWindowProp("foo", 123);
      console.log(window.foo);         // 123
      
      sandbox.deactivate();            // 卸載應用
      console.log(window.foo);         // undefined(被刪除)

      ProxySandbox(代理沙箱,多實例沙箱)

      ProxySandbox 可以說是 qiankun 沙箱的“終極形態”,現代瀏覽器環境下的主力方案。前面說的兩種沙箱存在下面的問題

      • SnapshotSandbox:全量快照,對比恢復,性能差。
      • LegacySandbox:單實例(只能一個子應用同時運行),多個并行時會沖突。

      為了解決 性能 + 并行運行 的問題,引入了 ProxySandbox

      它的核心是 ES6 的 Proxy,攔截對 window 的訪問:

      • 給每個子應用創建一個「假的 window」對象(稱為 fakeWindow)。
      • fakeWindow 的原型指向真正的 window,這樣子應用能正常訪問到全局屬性。
      • 子應用對全局變量的 修改、刪除、新增 都只會作用在 fakeWindow 上,而不會污染真實的 window
      • 不同子應用有不同的 fakeWindow,天然實現多實例隔離。
      // 1. 創建 ProxySandbox
      function createProxySandbox() {
        // 創建一個空對象 沒有原型鏈。
        const fakeWindow = Object.create(null);
        return new Proxy(fakeWindow, {
          get(target, prop) {
            if (prop in target) {
              return target[prop]; // 優先取子應用自己的
            }
            return window[prop];   // 否則取宿主的全局
          },
          set(target, prop, value) {
            target[prop] = value;  // 寫只寫在 fakeWindow 上
            return true;
          }
        });
      }
      
      // 2. 模擬子應用執行環境
      function runInSandbox(code, sandbox) {
        const wrapper = new Function("window", `
          with(window) {
            ${code}
          }
        `);
        wrapper(sandbox); // 關鍵:傳入 proxy
      }
      
      // 3. 使用
      const sandbox1 = createProxySandbox();
      const sandbox2 = createProxySandbox();
      
      runInSandbox(`window.foo = "app1"; console.log("app1 foo =", window.foo);`, sandbox1);
      runInSandbox(`window.foo = "app2"; console.log("app2 foo =", window.foo);`, sandbox2);
      
      console.log("真實 window.foo =", window.foo); // undefined,沒有污染

      new Proxy(fakeWindow, handler)

      這里的邏輯簡化一下主演干了下面的事情:

      • get
        讀屬性時觸發。優先取 fakeWindow,否則兜底真實 window
        ?? 寫過的值會“遮擋”宿主值。
      • set
        寫屬性時觸發。只寫入 fakeWindow,不污染真實 window
      • has
        with 語句查找變量時觸發。返回 prop in fakeWindow || prop in window
        ?? 確保像 consoledocument 這些全局在子應用里能被正常訪問。
      • deleteProperty
        刪除屬性時觸發。只刪 fakeWindow 的內容,不影響真實 window

      runInSandbox 是如何把子應用“綁”到 proxy 的

      const wrapper = new Function("window", `
        with(window) {
          ${code}
        }
      `);
      wrapper(proxy);
      • new Function("window", "with(window){ ... }") 創建了一個函數,函數參數名是 window
      • wrapper(proxy) 把我們造的 proxy 作為形參 window 傳入。
      • with(window) { ... } 會把這個 window(即 proxy)加入當前作用域鏈,所以代碼里的未限定標識符(比如 foo location document )會先在 proxy 上被查找/操作
      • 結合上面的 get/set/has,所有讀取/寫入都會被代理到 handler,從而實現攔截。

      CSS 隔離原理

      qiankun 沒有強制啟用某種隔離,而是給開發者提供了幾種選擇:

      • 默認:無強隔離, 子應用樣式直接插入主應用 head,容易污染,但性能最好。
      • StrictStyleIsolation(嚴格隔離): 使用 Shadow DOM 把子應用包裹起來。
      registerMicroApps(apps, {
        sandbox: { strictStyleIsolation: true }
      })

      這種方式的優點是徹底隔離,但某些全局樣式/第三方庫不兼容

      • ExperimentalStyleIsolation(實驗性隔離): 給子應用容器加 data-qiankun="xxx" 屬性,然后動態給所有 CSS 規則加前綴。
      registerMicroApps(apps, {
        sandbox: { experimentalStyleIsolation: true }
      })
      這種范式類似 Vue 的 scoped CSS,兼容性比 Shadow DOM 更好。

      本文轉載于:https://juejin.cn/post/7542506863206383668

      如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

      posted @ 2025-09-01 17:49  林恒  閱讀(120)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 18成禁人视频免费| 国产午夜福利不卡在线观看| 中文字幕人妻丝袜美腿乱| 色综合久久久久综合99| 中文字幕人妻av12| 日韩乱码视频一区二区三区| 日韩有码精品中文字幕| 艳妇臀荡乳欲伦交换在线播放| 亚洲国产精品久久久久婷婷图片| 国产精品一区二区三区色| 毛片在线播放网址| 亚洲人妻中文字幕一区| 亚洲 中文 欧美 日韩 在线| 吃奶还摸下面动态图gif| 成人亚欧欧美激情在线观看| 亚洲自拍精品视频在线| 四虎库影成人在线播放| 亚洲精品国产无套在线观| 极品尤物被啪到呻吟喷水| av无码精品一区二区乱子| 亚洲欧美人成人综合在线播放 | 少妇粗大进出白浆嘿嘿视频| 精品久久久久久无码免费| 国产69精品久久久久人妻刘玥| 久久国内精品一国内精品| 暖暖影院日本高清...免费| 亚洲欧美中文字幕5发布| 久久精品国产蜜臀av| 青青在线视频一区二区三区| 日韩中文字幕高清有码| 999精品色在线播放| 在线涩涩免费观看国产精品| 欧美xxxxx高潮喷水| 久久九九日本韩国精品| 韩国青草无码自慰直播专区| 国产精品自在线拍国产手机版| 国产无遮挡又黄又爽不要vip软件| 风流少妇树林打野战视频| 国产成人精品中文字幕| 日本激情久久精品人妻热| 国产精品激情av在线播放|