Изолировать выполнение JavaScript

Одно из ограничений JS, которое меня больше всего беспокоит, - это низкая способность изолировать выполнение кода.

Я хочу иметь возможность контролировать контекст, в котором выполняется код. Что-то, что обеспечивает аналогичный эффект для того, что Script.createContext и Script.runInContext в node.js делает (node использует привязку к V8, поэтому я не могу имитировать их реализацию).

Вот почему я хочу изолировать выполнение кода:

  • Изолируйте код из глобального пространства имен (объект window и также DOM), но мне, однако, нужно иметь возможность вызова ссылочной функции для объектов, открытых в контексте, которые должны выполняться синхронно, что делает его почти невозможно использовать WebWorker для изоляции.
  • Отключив выполнение кода, вы также сможете освободить его определения, когда они больше не нужны (управление памятью).

Я знаю, что можно выполнить частично изолированное выполнение, загрузив script в iframe, однако этот подход очень тяжелый и использует много памяти для второго экземпляра DOM, который не нужен для того, что я пытаясь сделать.

Мне нужно разделить определение конструктора, а также определения объекта, которые совместно используются изолированными контейнерами/контекстами, которые оба должны выполняться в основном потоке пользовательского интерфейса. В основном я хочу использовать эти изолированные контейнеры для размещения плагинов/модулей (мини-приложений), каждый из которых представляет и динамически обновляет окно просмотра, вызывая команды рисования на свой собственный объект Context2D.

Если эти контейнеры не работают в основном потоке пользовательского интерфейса, то это будет тяжело для прокси-вызовов, таких как ctx.measureText() и ctx.drawImage() будет бесполезным, поскольку объекты изображения не могут быть созданы в Worker.

Кто-нибудь знает о будущих спецификациях, которые сделают это возможным?

Существуют ли существующие (скрытые) API-интерфейсы на стороне браузера, которые можно было бы использовать для достижения этого?

Будет ли лучше использовать виртуальную машину, такую ​​как Goggle Dart VM, а также повторно реализовать мою текущую кодовую базу? Моя текущая база кода немного выше 20 000 строк кода.

Было бы лучше повторить реализацию фреймворка в *

Ответ 1

Вы можете изолировать свой код от глобального пространства имен с помощью простого объекта функции самоисполнения:

(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 или что-то вроде что. Общепринято объявлять один глобальный объект пространства имен и использовать свойства, недоступные для любого доступа к вещам, которые вы используете между модулями. Я знаю, что он не совсем совершенен, но он работает. Здесь пример rendevous, использующий один глобальный объект пространства имен:

// 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() {};

})();

Ответ 2

Ближайшая библиотека, которую я видел для этого, Caja.

В принципе, в нестандартном javascript-коде есть много способов получить доступ к глобальному объекту (window в браузерах), что делает настоящую изоляцию очень трудной проблемой. Caja делает некоторые интригующие трюки, чтобы исправить это, но, честно говоря, я не совсем уверен, как это работает.

Ответ 3

Является ли "стандартное" имя заменой опции? Как:

var myNamespace = {};

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

Этот подход является самым простым, о котором я могу думать и может быть решением многих проблем. Хотя это и не настоящая песочница, это может привести к тому, что код будет меньше подвержен ошибкам.

Ответ 4

Не могли бы вы использовать закрытие, как упомянутые другие ответы, а затем использовать теневое хранилище, чтобы пользователь не мог добраться до остальной части 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.
  • Вы должны быть очень осторожны, чтобы объекты, которые вы делаете, предоставляли доступ к изолированному коду, не содержат ссылок на то, к чему вы не хотите иметь доступ. Иногда это сверхпроблемная ошибка.
  • Я делаю это предложение, потому что его правдоподобно, что он работает, но я понятия не имею, есть ли дополнительные способы доступа к таким вещам, как окна и объекты документа.