微前端(wujie)源码解析-7.wujie-core沙箱运行

无界沙箱运行

前言

上一篇文章中,我们分析了无界的沙箱激活机制,沙箱激活过程中,将子应用的html模板渲染到webComponent中,但是距离子应用的运行还差一步,子应用的js还没有运行,本篇文章我们将一起分析沙箱的运行机制

运行js沙箱

沙箱的运行入口是start函数,函数的定义如下:

ts 复制代码
class Wujie {
    public async start(getExternalScripts: () => ScriptResultList): Promise<void> {
        // debugger
        this.execFlag = true;
        // 执行脚本
        const scriptResultList = await getExternalScripts();
        // 假如已经被销毁了
        if (!this.iframe) return;
        const iframeWindow = this.iframe.contentWindow;
        // 标志位,执行代码前设置
        iframeWindow.__POWERED_BY_WUJIE__ = true;
        // 同步代码
        const syncScriptResultList: ScriptResultList = [];
        
        scriptResultList.forEach((scriptResult) => {
            // other code 处理defer和async
            // 同步代码
            syncScriptResultList.push(scriptResult);
        });
        
        // 同步代码
        syncScriptResultList.forEach((scriptResult) => {
            this.execQueue.push(() =>
                scriptResult.contentPromise.then((content) =>
                    this.fiber
                        ? requestIdleCallback(() => insertScriptToIframe({ ...scriptResult, content }, iframeWindow))
                        : insertScriptToIframe({ ...scriptResult, content }, iframeWindow)
                )
            );
        });

        //框架主动调用mount方法
        this.execQueue.push(this.fiber ? () => requestIdleCallback(() => this.mount()) : () => this.mount());
        
        // 执行队列
        this.execQueue.shift()();

        // 所有的execQueue队列执行完毕,start才算结束,保证串行的执行子应用
        return new Promise((resolve) => {
            this.execQueue.push(() => {
                resolve();
                this.execQueue.shift()?.();
            });
        });
    }
}

上面的代码中,我们略作删减,留下一些关键代码,可以看到在start函数中,最终是要将子应用的js代码插入到iframe中,然后调用mount函数,实现的步骤如下:

  • 向执行队列execQueue中添加子应用js代码
  • 向执行队列execQueue中添加mount函数,当子应用挂载时调用
  • 依次执行队列execQueue中的函数

如下图所示:

如上所示使我们的队列中等待执行的函数,当我们调用 this.execQueue.shift()();时,就会执行队列中的函数,并且会串行的执行所有的队列中的代码,那么这是怎么实现的呢?我们通过一个例子来了解下:

这张图片中,蓝色的为我们的子应用代码,红色的为我们的mount函数,绿色的为我们的start函数,当我们执行队列中函数时,遇到子应用代码则插入到iframe中,遇到mount函数则调用mount函数,当队列中的函数执行完毕时,start函数才算执行完毕. 在执行子应用代码时,有一个特殊的处理,为了保证队列执行的延续性,在一个子应用代码执行完毕后,会像iframe中插入一段辅助代码"if(window.__WUJIE.execQueue && window.__WUJIE.execQueue.length){ window.__WUJIE.execQueue.shift()()}";,这样就保证了队列中所有函数的的串行执行。如下图所示:

mount钩子函数

当我们的子应用代码执行完毕后,会调用mount函数,mount函数的定义如下:

ts 复制代码
class Wujie {
    public mount(): void {
        if (this.mountFlag) return;
        if (isFunction(this.iframe.contentWindow.__WUJIE_MOUNT)) {
            removeLoading(this.el);
            this.lifecycles?.beforeMount?.(this.iframe.contentWindow);
            this.iframe.contentWindow.__WUJIE_MOUNT();
            this.lifecycles?.afterMount?.(this.iframe.contentWindow);
            this.mountFlag = true;
        }
        this.execQueue.shift()?.();
    }
}

mount函数中,会调用子应用的__WUJIE_MOUNT函数,这个函数是子应用中定义的,如下我们在子应用中定义:

ts 复制代码
window.__WUJIE_MOUNT = () => {
    const router = new VueRouter({ base, routes });
    instance = new Vue({ router, render: (h) => h(App) }).$mount("#app");
};

所以当我们调用完mount函数后,子应用就会被挂载到我们的#app中,这样就完成了子应用的挂载

总结

本篇文章我们分析了无界的沙箱运行机制,无界的沙箱运行机制是通过一个队列来实现的, 当我们调用start函数时,会将子应用的js代码插入到iframe中,然后调用mount函数,这其中也有一些特殊的处理,比如在子应用代码执行完毕后,会像iframe中插入一段辅助代码来保证队列继续往后执行

最后的最后

关于无界的沙箱运行机制我们用了7篇文章来分析,从无界的整体架构,到适配层,再到核心层,在核心层中,我们又分析了沙箱的创建,激活,运行,这其中涉及到了很多的知识点,比如webComponentpxoxy等等,其中还有很多点我们没有深入分析, 但好在我们对整体的运行流程有了一个大概的了解,当我们以后想要分析某一块功能点时,也能够快速定位我们要分析的代码。

如果觉得本文有帮助 记得点赞三连哦 十分感谢!

系列链接

相关推荐
灵感__idea5 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea7 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd8 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌9 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈9 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫9 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝9 小时前
svg图片
前端·css·学习·html·css3
橘子编程9 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇10 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧10 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint