领域(realm),这个词比较抽象,其实就代表了一个 JavaScript 独立的运行环境,里面有独立的变量作用域。
创新互联公司长期为近千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为庆安企业提供专业的网站制作、成都网站制作,庆安网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。
比如下面的代码:
每个 iframe 都有一个独立的运行环境,document 的全局对象不同于 iframe 的全局对象,类似的,全局对象上的 Array 肯定也不同。
ShadowRealm API 是一个新的 JavaScript 提案,它允许一个 JS 运行时创建多个高度隔离的 JS 运行环境(realm),每个 realm 具有独立的全局对象和内建对象。
ShadowRealm 具有下面的类型签名:
declare class ShadowRealm {
constructor();
evaluate(sourceText: string): PrimitiveValueOrCallable;
importValue(specifier: string, bindingName: string): Promise;
}
每个 ShadowRealm 实例都有自己独立的运行环境,它提供了两种方法让我们来执行运行环境中的代码:
.evaluate() 的类型签名:
evaluate(sourceText: string): PrimitiveValueOrCallable;
.evaluate() 的工作原理很像 eval():
const sr = new ShadowRealm();
console.assert(
sr.evaluate(`'ab' + 'cd'`) === 'abcd'
);
但是与 eval() 不同的是,代码是在 .evaluate() 的独立运行环境中执行的:
globalThis.realm = 'incubator realm';
const sr = new ShadowRealm();
sr.evaluate(`globalThis.realm = 'ConardLi realm'`);
console.assert(
sr.evaluate(`globalThis.realm`) === 'ConardLi realm'
);
如果 .evaluate() 返回一个函数,为了方便在外部调用这个函数会被包装,然后在 ShadowRealm 中运行:
globalThis.realm = 'incubator realm';
const sr = new ShadowRealm();
sr.evaluate(`globalThis.realm = 'ConardLi realm'`);
const wrappedFunc = sr.evaluate(`() => globalThis.realm`);
console.assert(wrappedFunc() === 'ConardLi realm');
每当一个值传入 ShadowRealm 时,它必须是原始类型或者可以被调用的。否则会抛出异常:
> new ShadowRealm().evaluate('[]')
TypeError: value passing between realms must be callable or primitive
.importValue() 的类型签名:
importValue(specifier: string, bindingName: string): Promise;
你可以直接导入一个外部的模块,异步执行并返回一个 Promise,用法:
// main.js
const sr = new ShadowRealm();
const wrappedSum = await sr.importValue('./my-module.js', 'sum');
console.assert(wrappedSum('hi', ' ', 'folks', '!') === 'hi ConardLi!');
// my-module.js
export function sum(...values) {
return values.reduce((prev, value) => prev + value);
}
与 .evaluate() 一样,传入 ShadowRealms 的值(包括参数和跨环境函数调用的结果)必须是原始的或可调用的。
ShadowRealms 与 eval() 和 Function 很像,但比它们俩都好一点:我们可以创建新的JS运行环境并在其中执行代码,这可以保护外部的JS运行环境不受代码执行的操作的影响。
Web Worker 是一个比 ShadowRealms 更强大的隔离机制。其中的代码运行在独立的进程中,通信是异步的。
但是,当我们想要做一些更轻量级的操作时,ShadowRealms 是一个很好的选择。它的算法可以同步计算,更便捷,而且全局数据管理更自由。
前面我们已经提到了,每个 iframe 都有自己的运行环境,我们可以在里面同步执行代码。
与 ShadowRealms 相比,还是有以下缺点:
Node.js 的 vm 模块与 ShadowRealm API 类似,但具有更多功能:缓存 JavaScript 引擎、拦截 import() 等等。但它唯一的缺点就是不能跨平台,只能在 Node.js 环境下使用。
下面我们来看个在 ShadowRealms 中运行测试的小 Demo,测试库收集通过 test() 指定的测试,并允许我们通过 runTests() 运行它们:
// test-lib.js
const testDescs = [];
export function test(description, callback) {
testDescs.push({description, callback});
}
export function runTests() {
const testResults = [];
for (const testDesc of testDescs) {
try {
testDesc.callback();
testResults.push(`${testDesc.description}: OK\n`);
} catch (err) {
testResults.push(`${testDesc.description}: ${err}\n`);
}
}
return testResults.join('');
}
使用库来指定测试:
// my-test.js
import {test} from './test-lib.js';
import * as assert from './assertions.js';
test('succeeds', () => {
assert.equal(3, 3);
});
test('fails', () => {
assert.equal(1, 3);
});
export default true;
在下一个示例中,我们动态加载 my-test.js 模块来收集然后运行测试。
唉,目前还没有办法在不导入任何东西的情况下加载模块。
这就是为什么在前面示例的最后一行中有一个默认导出。我们使用 ShadowRealm .importvalue() 方法导入 default export 。
// test-runner.js
async function runTestModule(moduleSpecifier) {
const sr = new ShadowRealm();
await sr.importValue(moduleSpecifier, 'default');
const runTests = await sr.importValue('./test-lib.js', 'runTests');
const result = runTests();
console.log(result);
}
await runTestModule('./my-test.js');
jsdom 库创建了一个封装的浏览器环境,可以用来测试 Web 应用、从 HTML 中提取数据等。它目前使用的是 Node.js vm 模块,未来可能会更新为使用 ShadowRealms(后者的好处是可以跨平台,而 vm 目前只支持 Node.js)。
新闻标题:比Eval和Iframe更强的新一代JavaScript沙箱!
文章地址:http://www.shufengxianlan.com/qtweb/news6/110206.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联