低代码系列——js沙箱设计(一)

简介: 由于自己参与过低代码平台开发,所以希望能把我自己开发低代码中遇到的问题或者一些设计思路进行总结汇总,这是开始写的第一篇,也是比较基础的一篇,关于低代码平台的介绍会放在介绍篇章,这篇就不做过多介绍。

简介


由于自己参与过低代码平台开发,所以希望能把我自己开发低代码中遇到的问题或者一些设计思路进行总结汇总,这是开始写的第一篇,也是比较基础的一篇,关于低代码平台的介绍会放在介绍篇章,这篇就不做过多介绍。


这里为什么会一开始介绍js沙箱设计呢?


因为低代码平台,会运行用户本身自己编写的业务逻辑代码,这里就需要平台去运行用户写的js代码,但是js代码保存到数据库是一个字符串,那么平台应该怎么运行呢?


答案是js沙箱,那么如何设计一个沙箱呢?按照低代码平台的需要特性,主要以下几方面:

  • 隔离,隔离是为了保证当前执行代码不影响整个平台的代码
  • 插入,沙箱允许插入平台的内置对象
  • 容错,沙箱内代码即使有错误,也不影响整个平台执行

沙箱


在设计沙箱之前,我们先对沙箱有个了解:

在计算机安全中,沙箱(Sandbox)是一种用于隔离正在运行程序的安全机制,通常用于执行未经测试或不受信任的程序或代码,它会为待执行的程序创建一个独立的执行环境,内部程序的执行不会影响到外部程序的运行。

通俗的讲,就是由我们主程序自己设定一个区域,用来执行代码,且这段代码如何执行都不会影响到外部的主程序。


举几个我们开发中经常会用的沙箱:

  • Vue template里的表达式,如:

    {{ 1+1 }}

    ,执行1+1就是Vue设计的一个沙箱机制
  • 开发Chrome插件,插件里的代码有很多限制条件,循序Chrome插件规则,那么插件的运行环境和规则也是一个沙箱
  • 在线代码编辑器, CodeSanbox在执行脚本也会单独成立一个沙箱去隔离执行代码,防止代码访问或影响主页面
  • 微前端qiangunsingle-spa 框架里主应用和子应用之间的完全隔离,也是一种沙箱机制,如: 应用之间CSS样式不能互相影响


在了解完沙箱是什么后,那么在JavaScript语言里如何实现沙箱呢?主要有以下几种方式:

  • 使用 with 声明
  • 使用 new Function 声明
  • 基于 Proxy实现
  • 基于属性 diff实现
  • 基于 iframe实现
  • 基于 ES 提案 ShadowRealm API

前置知识


with关键字


with 扩展一个语句的作用域链。 —— MDN withJavaScript 查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的 context 或者包含这个变量的函数有关。'with'语句将某个对象添加到作用域链的顶部,如果在 statement 中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出ReferenceError异常。

按照个人比较容易理解的意思,就是给一段代码加上指定对象为该作用的全局变量。示例代码如下:

Math.floor(1.1) // 1
// 使用with
with(Math){
    floor(1.1) // 1
}

new Function

new Function(argStr, codeStr)是能将字符串代码转换为可执行的函数。具体示例如下:

const name = 'test';
const test = new Function('arg', 'console.log(arg)');
// 这里等于 test = (arg)=> {console.log(arg)};
test(name); // test


Proxy


Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。Proxy MDN

Proxy只能代理object类型的变量,针对基础类型的代理只能将其封装到对象里再进行代理监听。


Proxy代理方法如下:

  • getPrototypeOf(target) 代理获取原型的方法
  • setPrototypeOf(target, newProto) 设置原型,如果不想设置原型,可以return false
  • isExtensible(target)  拦截对对象的 Object.isExtensible(),必须返回一个 Boolean 值,判断一个对象是否是可扩展的
  • preventExtensions(target) 拦截Object.preventExtensions(),让一个对象变的不可扩展,也就是永远不能再添加新的属性
  • getOwnPropertyDescriptor(target, prop) 拦截Object.getOwnPropertyDescriptor(),拦截获取对象属性的描述符
  • defineProperty(target, property, descriptor) 拦截Object.defineProperty()
  • has(target, key),针对 in 操作符的代理方法
  • get(target, property, receiver),用于拦截对象的读取属性操作
  • set(),设置属性值操作的捕获器。
  • construct(),用于拦截 new 操作符


Object.defineProperty主要区别(可拦截方法比Object.defineProperty多):

  • Proxy代理的是整个对象,Object.defineProperty只代理对象上的某个属性,如果是多层嵌套的数据需要循环递归绑定;
  • 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到,需要借助$set方法;
  • 数组的某些方法(push、unshift和splice)Object.defineProperty监听不到,Proxy可以监听到;

Symbol.unscopables


指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。

可以这么理解,就是为了防止with添加作用域的时候,将某个属性从作用域中排除掉,代码如下:

a = {
    p: 1,
    b: 2
}
// 禁止将a.p放到with作用域中
a[Symbol.unscopables] = {p: true}
with(a){
    console.log(p) // 报错 p not defined
    console.log(b) // 正常输出
}

因此很多内置对象都设置该值为true,从而降低with的侵入,具体如下:

Array.prototype[Symbol.unscopables];
/*{
  copyWithin: true,
  entries: true,
  fill: true,
  find: true,
  findIndex: true,
  flat: true,
  flatMap: true,
  includes: true,
  keys: true,
  values: true,
}*/


目录
相关文章
|
网络协议 Windows
解决GitHub Pages制作的个人博客无法访问的问题
最近一段时间应该有很多小伙伴发现自己辛苦做的个人博客无法访问了吧。
|
资源调度 前端开发 算法
前端依赖版本重写指南
感谢神奇的 Semver 动态规则,npm 社区经常会发生依赖包更新后引入破坏变更的情况(应用没有使用依赖锁的话),而应用开发者就要在自己的依赖声明里先临时绕过,避免安装到有问题的版本,如果是一级依赖,只需要改 package.json 的声明就可以了,但如果是子依赖,就需要进行版本重写(overrides/resolution)了。本文是一篇针对版本重写功能的指南性文章,当你遇到如下的问题时,就可以按照对应的依赖重写语法,解决这些依赖问题了。
8554 1
前端依赖版本重写指南
|
Web App开发 缓存 网络协议
解决Github不能下载,下载速度慢的小妙招
解决Github不能下载,下载速度慢的小妙招
解决Github不能下载,下载速度慢的小妙招
|
6月前
|
机器学习/深度学习 人工智能 前端开发
终端里的 AI 编程助手:OpenCode 使用指南
OpenCode 是开源的终端 AI 编码助手,支持 Claude、GPT-4 等模型,可在命令行完成代码编写、Bug 修复、项目重构。提供原生终端界面和上下文感知能力,适合全栈开发者和终端用户使用。
53267 11
|
人工智能 缓存 NoSQL
Redis 与 AI:从缓存到智能搜索的融合之路
Redis 已从传统缓存系统发展为强大的 AI 支持平台,其向量数据库功能和 RedisAI 模块为核心,支持高维向量存储、相似性搜索及模型服务。文章探讨了 Redis 在实时数据缓存、语义搜索与会话持久化中的应用场景,并通过代码案例展示了与 Spring Boot 的集成方式。总结来看,Redis 结合 AI 技术,为现代应用提供高效、灵活的解决方案。
|
存储 JavaScript 前端开发
如何在 React Hooks 中使用 Redux?
【10月更文挑战第1天】
|
缓存 前端开发 JavaScript
理解 React 的 Fiber 架构
【8月更文挑战第6天】 理解 React 的 Fiber 架构
1174 1
|
存储 JSON 前端开发
react保姆级搭建新项目
此文主要以ts+vite+router6+antd 快速搭建一个react项目,适用于初学者,用于学习交流
636 2
|
缓存 JavaScript 前端开发
低代码系列——js沙箱设计(二)
由于自己参与过低代码平台开发,所以希望能把我自己开发低代码中遇到的问题或者一些设计思路进行总结汇总,这是开始写的第一篇,也是比较基础的一篇,关于低代码平台的介绍会放在介绍篇章,这篇就不做过多介绍。
754 0
|
人工智能 搜索推荐 云栖大会
什么是通义智文?AI阅读助手,用AI帮你读得多、读得快、读得懂
介绍通义智文产品发展历程、使用场景及主要功能。
53604 9

热门文章

最新文章