关于qiankun沙箱sandbox

为什么要有js资源隔离机制?

主应用和子应用,相同的全局变量,可能会发生冲突,子应用和子应用之间,相同的全局变量,也可能会发生冲突。在这里我们主要指的就是window。

思路:打开沙箱时能够修改属性值;关闭沙箱时恢复未开启沙箱前的属性值,并且要记录修改了哪些属性。

qiankun.js隔离机制

SnapshotSandBox

快照沙箱,支持单个微应用

  1. class SnapShotBox {
  2. windowSnap = {} //保存window上原本的属性值
  3. modifyPropMap = {} //记录修改的属性
  4. //微应用激活状态
  5. active() {
  6. //保存window对象上所有属性的状态
  7. for (const prop in window) {
  8. this.windowSnap[prop] = window[prop]
  9. }
  10. //恢复上一次在运行该微应用时所修改过的window上的属性
  11. Object.keys(this.modifyPropMap).forEach(prop => {
  12. window[prop] = this.modifyPropMap[prop];
  13. })
  14. }
  15. //微应用未激活状态
  16. inactive() {
  17. for (const prop in window) {
  18. //判断是否值发生了变化
  19. if (window[prop] !== this.windowSnap[prop]) {
  20. //记录修改了window上的哪些属性
  21. this.modifyPropMap[prop] = window[prop]
  22. //将window上的属性状态还原至微应用运行之前的状态
  23. window[prop] = this.windowSnap[prop]
  24. }
  25. }
  26. }
  27. }
  28. const snapShotBox = new SnapShotBox()
  29. window.city = 'Beijing'
  30. console.log(window.city); //Beijing
  31. snapShotBox.active()
  32. window.city = 'Shanghai'
  33. console.log(window.city); //Shanghai
  34. snapShotBox.inactive()
  35. console.log(window.city); //Beijing

完成了一个简易沙箱,但是会遍历window的所有属性,非常消耗性能,方案不是很可取,与此同时,影响了window上的值,如果多个微应用就可能会产生冲,只能激活一个微应用。

LegacySandBox
  1. class LegacySandBox {
  2. currentUpdatePropsValueMap = new Map() //微应用中修改的属性
  3. modifiedPropsOriginValueMapInSanBox=new Map()//window中被修改的属性
  4. addedPropsMapInSandBox=new Map() //添加的属性
  5. proxyWindow={}
  6. constructor(){
  7. const fakeWindow = Object.create(null)
  8. this.proxyWindow = new Proxy(fakeWindow,{
  9. set:(target,prop,value,receiver)=>{
  10. const originalVal = window[prop]
  11. if(!window.hasOwnProperty(prop)){ //如果window上没有这个属性,那么就是新增的属性
  12. this.addedPropsMapInSandBox.set(prop,value)
  13. //如果修改对象中没有这个属性,就保存一下
  14. }else if(!this.modifiedPropsOriginValueMapInSanBox.has(prop)){
  15. this.modifiedPropsOriginValueMapInSanBox.set(prop,originalVal)
  16. }
  17. this.currentUpdatePropsValueMap.set(prop,value)
  18. window[prop] = value
  19. },
  20. get:(target,prop,receiver)=>{
  21. return window[prop]
  22. },
  23. })
  24. }
  25. //设置window属性
  26. setWindowProp(prop, value, isToDelete) {
  27. if (value == "undfined" && isToDelete) {
  28. delete window[prop]
  29. } else {
  30. window[prop] = value
  31. }
  32. }
  33. //微应用激活状态
  34. active() {
  35. //恢复上一次在运行该微应用时所修改过的window上的属性
  36. this.currentUpdatePropsValueMap.forEach((value, prop) => {
  37. this.setWindowProp(prop, vaue);
  38. })
  39. }
  40. //微应用未激活状态
  41. inactive() {
  42. //还原window上原有的属性
  43. this.modifiedPropsOriginValueMapInSanBox.forEach((value,prop)=>{
  44. this.setWindowProp(prop,value)
  45. })
  46. //删除微应用运行期间,window上新增的属性
  47. this.addedPropsMapInSandBox.forEach((_,prop)=>{
  48. this.setWindowProp(prop,undefined,true)
  49. })
  50. }
  51. }
  52. let legacySandbox = new LegacySandBox()
  53. window.city = 'Beijing'
  54. console.log(window.city); //Beijing
  55. snapShotBox.active()
  56. window.city = 'Shanghai'
  57. console.log(window.city); //Shanghai
  58. snapShotBox.inactive()
  59. console.log(window.city); //Beijing

不需要遍历window上的所有属性,性能良好,但是依然改变的是window上的值,但同一时间还是只能激活一个微应用。

ProxySandBox
  1. class ProxySandBox {
  2. proxyWindow;
  3. isRunning = false
  4. //微应用激活状态
  5. active() {
  6. this.isRunning = true
  7. }
  8. //微应用未激活状态
  9. inactive() {
  10. this.isRunning = false
  11. }
  12. constructor() {
  13. const fakeWindow = Object.create(null)
  14. this.proxyWindow = new Proxy(fakeWindow, {
  15. set: (target, prop, value, receiver) => {
  16. if (this.isRunning) {
  17. target[prop] = value
  18. }
  19. },
  20. get: (target, prop, receiver) => {
  21. return prop in target ? target[prop] : window[prop]
  22. }
  23. })
  24. }
  25. }
  26. window.city = 'Beijing'
  27. let proxySandBox01 = new ProxySandBox()
  28. let proxySandBox02 = new ProxySandBox()
  29. proxySandBox01.active()
  30. proxySandBox02.active()
  31. proxySandBox01.proxyWindow.city = "Shanghai"
  32. proxySandBox02.proxyWindow.city = "Tianjing"
  33. console.log(window.city, proxySandBox01.proxyWindow.city, proxySandBox02.proxyWindow.city);
  34. //Beijing Shanghai Tianjing
  35. proxySandBox01.inactive()
  36. proxySandBox02.inactive()
  37. console.log(window.city, proxySandBox01.proxyWindow.city, proxySandBox02.proxyWindow.city);
  38. //Beijing Shanghai Tianjing

这种ProxySandBox不需要遍历window上的所有属性,性能良好,同一时间可以激活多个微应用互不干扰。

SnapshotSandBox兼容性很好ProxySandBox适用于es6的语法中,就简单介绍到这里。

posted @ 2024-03-22 10:07  mounter爱学习  阅读(91)  评论(0编辑  收藏  举报