本文已参与「新人创作礼」活动,一起开启掘金创作之路
随着应用架构复杂,微前端方案的出现,js运行环境沙箱在浏览器中的需求越来越多
需要js沙箱的场景
- 多个微前端应用中,变量冲突
- 执行第三方js:当你有必要执行第三方js的时候,而这份js文件又不一定可信的时候
需要实现的功能
一个独立的上下文作用域,其中的代码执行不会影响到其他的运行环境。 需要支持多个沙箱环境存在,每个沙箱需要有加载、卸载、再次恢复的能力,其对应着微应用的运行生命周期。
实现过程
上面的get/set条件不够完善,应该使用如下:
1、核心是使用
proxy对象创建window代理,并将需要被隔离起来的代码的执行作用域绑定到proxy对象上
2、属性active用来外界控制沙箱是否运行
3、new set()injectedKeys用于记录添加的属性,在沙箱停止的时删除
4、使用Reflect高级地实现属性操作
5、with和call把window的执行绑定到proxyWindow上
微前端应用:
5、微应用初始化的时候 new sandbox
6、ajax获取script标签的代码,并调用bindScope方法用eval在全局作用域执行
7、webpack打包后动态加载的js是使用document.createElement在head里增加了script标签,浏览器自动执行。则对document.createElement重新复制并代理src属性的get和set,在set中获取js内容并在沙箱中执行
proxy:new Proxy(target, handler),handler中指定对象的属性的get、set等操作。详见MDNObject.defineProperty:对象的某个属性的操作进行代理Object.defineProperty(obj, prop, descriptor),descriptor中(value、writable)与(get、set)是两者其中之一,不能同时都有,详见MDN 题外话:vue3 /2 分别用上述原理实现响应式Reflect:和直接对象赋值没有区别,优点在于可以知道set的结果成功/失败,且不会因为报错而中断正常的代码逻辑执行,还有厉害的receiver参数,详见:张鑫旭eval(string)工作在当前作用域下,会将传入的字符串当做 JavaScript 代码进行执行。使用引用或者(0, eval)('x + y')会工作在全局作用域下 题外话:eval的使用with语句 扩展一个语句的作用域链,指定代码执行的默认对象。详见:MDN
一些优化
1、实现沙箱的再次恢复 2、不使用eval和with来实现对应功能