Javascript 沙箱 ShadowRealms

Javascript 阴影领域

这听起来黑暗而神秘——但它只是另一个未来的 Javascript 特性。ShadowRealm是 Javascript的一项新功能,它将让我们创建一个单独的全局上下文来执行 Javascript。在本文中,我们将了解什么是 ShadowRealm 及其工作原理。

在 Javascript 中支持 ShadowRealms#

ShadowRealms 是一个 Javascript 提案,目前处于第 3 阶段。因此,ShadowRealms 在浏览器或服务器端语言(如 Node.JS)中不支持,并且考虑到它多年来发生了许多变化,因此没有稳定的 babel 或 npm插件来填充功能。然而,鉴于它已经达到第 3 阶段,这意味着未来不会有太多变化,我们可以期待ShadowRealms 在未来的某个时候获得原生支持。

Javascript 中的 ShadowRealms 是如何工作的#

AShadowRealm最终是一种使用不同的全局对象设置全新环境的方法,将代码与其他领域分开。当我们在 Javascript 中谈论全局对象时,我们指的是windowor的概念globalThis最终试图解决的问题ShadowRealm减少不同代码集之间的冲突,并为需要隔离运行的代码的执行和运行提供安全的环境。这意味着其他代码或包对全局对象的污染更少。因此,a 中的代码ShadowRealm无法与不同领域中的对象进行交互。

ShadowRealm 用例:

  • 代码编辑器,用户可以在其中编辑代码,我们不想与主网页进行交互。
  • 可以独立执行的插件。
  • 在单独的环境中模拟 DOM,即如果我们需要知道某些场景中的滚动位置,我们可以在 a 中模拟它,ShadowRealm这样用户在主网页上滚动就不会影响window.top我们模拟中的变量。

ShadowRealm它与所有其他 Javascript 在同一个线程上运行 – 所以如果你想多线程你的 Javascript,你仍然必须使用Web Workers。因此,aShadowRealm可以存在于 worker 中,也可以存在于常规 Javascript 文件中。ShadowRealms 甚至可以存在于其他ShadowRealms 中。

在 Javascript 中创建 ShadowRealm#

让我们看看 aShadowRealm在代码中的实际表现。我们要做的第一件事是调用一个新ShadowRealm实例。然后我们可以将一些 Javascript 导入我们的领域,它将在其中运行。为此,我们使用一个名为 的函数importValue,它的工作方式与 相同import

let myRealm = new ShadowRealm();

let myFunction = await myRealm.importValue('./function-script.js', 'analyseFiles');

// Now we can run our function within our ShadowRealm
let fileAnalysis = myFunctions();

在上面的示例中,analyseFiles是我们从function-script.js导入的导出名称。然后我们捕获此导出并将其存储在myFunction. 重要的是,我们导入到我们领域的导出必须是可调用的,因此它必须是我们可以运行的有效函数。

我们的function-script.js文件只是一个带有导出的普通 Javascript 文件。它可能看起来像这样:

export function analyseFiles() {
    console.log('hello');
}

TheShadowRealm与我们可能拥有的其他全局对象完全分开,例如windowor globalThis

与其他导入类似,我们可以使用大括号导入符号:

let myRealm = new ShadowRealm();

const { runFunction, testFunction, createFunction } = await myRealm.importValue('./function-script.js');

let fileAnalysis = runFunction();

importValue或者,如果我们想使用命名的 s ,我们可以创建多个全部转换为数组的承诺。

let myRealm = new ShadowRealm();

const [ runFunction, testFunction, createFunction ] = await Promise.all([
    myRealm.importValue('./file-one.js', 'runFunction'),
    myRealm.importValue('./file-two.js', 'testFunction'),
    myRealm.importValue('./file-three.js', 'createFunction'),
]);

let fileAnalysis = runFunction();

在 ShadowRealms 中使用评估执行代码

如果我们想直接在 ShadowRealm 中执行代码,而不是来自另一个文件,我们可以使用evaluateShadowRealm 上的方法来执行一串 Javascript。这与以下工作方式大致相同eval()

let myRealm = new ShadowRealm();

myRealm.evaluate(`console.log('hello')`);

ShadowRealm importValue 是 thennable

由于importValue返回一个承诺,它的价值是 thennable。这意味着我们可以使用then()它,然后用它返回的输出函数做一些事情。例如:

window.myVariable = 'hello';
let myRealm = new ShadowRealm();

myRealm.importValue('someFile.js', 'createFunction').then((createFunction) => {
    // Do something with createFunction();
    console.log(window.myVariable); // Returns undefined
})

很酷的一点是全局对象不会泄漏到then()语句中。所以window.myVariable是未定义的。这为我们提供了一个完全隔离的代码区域,我们不必担心来自全局对象的干扰!

我们也可以使用这种方法来访问定义在someFile.js. 例如,假设我们更改someFile.js为:

globalThis.name = "fjolt";

export function returnGlobals(property) {
  return globalThis[property];
}

现在,在我们的then函数中,我们可以获得以下值globalThis.name

window.myVariable = 'hello';
let myRealm = new ShadowRealm();

myRealm.importValue('someFile.js', 'returnGlobals').then((returnGlobals) => {
    // Do something with returnGlobals();
    console.log(returnGlobals("name")); // Returns fjolt
    console.log(window.myVariable); // Returns undefined
})

结论#

今天,iframes 是我们通常在 web 上分离出不同环境的方式。iframes 很笨重,使用起来会很烦人。ShadowRealm另一方面,s 更高效,允许我们轻松地与我们现有的代码库集成,并与 Web Workers等现代 Javascript 技术很好地集成。

鉴于它们为代码执行提供一个独立区域的独特价值主张,它根本不与代码库的其余部分交互,ShadowRealms 很可能成为编写 Javascript 代码的主要工具。它们可能成为包和模块导出其内容的重要方式,而无需担心来自代码库其他部分的干扰。因此,期待看到它们在未来突然出现。

在此处阅读有关 ShadowRealm 规范的信息。