17

JS 最让我烦恼的限制之一是隔离代码执行的能力很差。

我希望能够控制执行代码的上下文,与 node.js 中的Script.createContext&实现类似效果的东西Script.runInContext(节点正在使用绑定到 V8 引擎,所以我无法模拟它们的实现)。

这是我想隔离代码执行的一些原因:

  1. 将代码与全局命名空间(window对象和DOM)隔离,但是我需要能够对上下文中公开的对象引用函数调用,这些对象必须同步执行,这使得使用 aWebWorker进行隔离几乎不可能。
  2. 通过隔离代码的执行,还可以在不再需要时释放其定义(内存管理)。

我知道可以通过将脚本加载到iframe.

我需要共享构造函数定义以及在隔离容器/上下文之间共享的对象定义,它们都必须在主 UI 线程上运行。主要是我想使用这些隔离的容器来托管插件/模块(迷你应用程序),每个插件/模块都通过在自己的Context2D对象上调用绘图命令来呈现和动态更新视口。

如果这些容器没有在主 UI 线程上运行,那么代理调用将非常困难,ctx.measureText()因为ctx.drawImage()图像对象无法在Worker.

有人知道未来的规范会使这成为可能吗?

是否有任何当前(隐藏的)浏览器端 API 可用于实现此目的?

使用像 Goggle 的 Dart VM 这样的虚拟机并重新实现我当前的代码库会更好吗? 我目前的代码库略高于 20 000 行代码。

在 * 中重新实现框架会更好吗

4

5 回答 5

3

您可以使用简单的自执行函数对象将代码与全局命名空间隔离:

(function() {
   // all your code goes here
   // nobody outside of your code can reach your top level variables here
   // your top level variables are not on the window object

   // this is a protected, but top level variable
   var x = 3;

   // if you want anything to be global, you can assign it to the window object.
   window.myGlobal = {};

   function myTopLevelFunction(x,y,z) {
       // code here
   }

})();

如果你想拥有多个这样的执行上下文并能够在它们之间共享,那么你将不得不通过一个公开的位置进行集合,或者是一个真正的全局变量,或者一个已知 DOM 对象上的属性或类似的东西。声明一个全局命名空间对象并使用其属性来访问您在模块之间共享的东西是相对常见的。我知道它并不完全完美,但它确实有效。这是使用单个全局命名空间对象的会合示例:

// module AAA
(function() {
   // module AAA code goes here

   // set up global namespace object and whatever references we want to be global
   window.myModuleTop = window.myModuleTop || {};
   myModuleTop.AAA = {};
   myModuleTop.AAA.myFuncA = function() {};

})();


// module BBB
(function() {
   // module BBB code goes here

   // set up global namespace object and whatever references we want to be global
   window.myModuleTop = window.myModuleTop || {};
   myModuleTop.BBB = {};
   myModuleTop.BBB.myFuncB = function() {};

})();
于 2012-04-29T23:06:01.177 回答
3

我见过的最近的图书馆是Caja

基本上,在非严格的 javascript 代码中,有很多方法可以访问全局对象(window在浏览器中),这使得真正的隔离成为一个非常困难的问题。Caja 做了一些 iframe 技巧来修补这个问题,但老实说,我不确定它是如何工作的。

于 2012-04-29T23:07:44.077 回答
2

您不能像提到的其他答案那样使用闭包,然后使用影子 dom 来确保用户无法访问 dom 的其余部分吗?像这样的东西:

var containerNode = someDomNode
var root = containerNode.createShadowRoot()
;(function(root){
  var window = null, document = null, history = null,
      screen = null, navigator = null, location = null

  // isolated code goes here

})(root)

注意事项:

  • 如果您在隔离代码的上下文之外创建其他全局对象,您需要像我对窗口、文档等所做的那样显式地隐藏变量,否则隔离代码将访问它。
  • 这显然不适用于没有影子 dom 的浏览器,除非您的隔离代码根本不需要与 dom 交互。
  • 您必须非常小心,您确实授予隔离代码访问权限的对象不包含对您希望它访问的内容的引用。有时这是超级容易犯的错误。
  • 我提出这个建议是因为它似乎可行,但我不知道是否有其他方法可以获取诸如窗口和文档对象之类的东西。
于 2015-10-12T20:26:07.717 回答
1

“标准”命名空间是一种选择吗?喜欢:

var myNamespace = {};

myNamespace.myFunc = function() { return true; }

这种方法是我能想到的最简单的方法,可能是许多问题的解决方案。虽然不是真正的沙箱,但它可以让代码不易出错。

于 2012-04-30T00:35:53.837 回答
0

有一个Realms API 提案,似乎可以解决类似的问题。它仍在讨论中,但已经有一个 polyfill 用于它 - realms-shim

于 2019-11-19T20:01:50.580 回答