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