微前端(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等等,其中还有很多点我们没有深入分析, 但好在我们对整体的运行流程有了一个大概的了解,当我们以后想要分析某一块功能点时,也能够快速定位我们要分析的代码。

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

系列链接

相关推荐
陈随易9 小时前
在Finch用了62亿词元,我认为这是新一代Agent工具之神
前端·人工智能·后端
水域安全老周9 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络
计算机魔术师10 小时前
Anthropic CEO突然喊踩刹车,OpenAI罕见力挺:AI这辆车不能只踩油门了
前端
wing9810 小时前
从codex转战workbuddy使用一周的感受
前端·人工智能·后端
Highcharts.js10 小时前
常见报错排雷指南2:导出失败的官方解法
javascript·react.js·ecmascript·highcharts·可视化图表·导出模块失败·导出服务
EatFan10 小时前
Java接入支付宝 JSAPI 支付保姆教程(二):流程讲解与前后端代码讲解
前端·spring boot·后端·微信小程序·小程序·uni-app
梦想平凡11 小时前
百游棋牌源代码开发搭建教程(五):房间创建、座位分配与请求幂等实现
前端·javascript·数据库·源代码管理
IT_陈寒11 小时前
Redis的Set操作居然能把我的服务整挂了?
前端·人工智能·后端
计算机魔术师11 小时前
Suno 发布 v6 音乐模型,推出 v6、v6-wild、v6-mini 三个版本
前端
whyweplay12 小时前
elpis : DSL动态组件学习
前端