当前位置: 华文头条 > 推荐

.NET 全面拥抱 Javascript,Jint 火了

2024-02-05推荐

大家好,很高兴又见面了,我是" 高级前端‬进阶 ‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

1.什么是 Jint

Jint 是 .NET 的 Javascript 解释器,可以在任何现代 .NET 平台上运行,支持 .NET Standard 2.0 和 .NET 4.6.2 目标(及更高版本)。在性能方面,Jint 也是非常优秀:

  • 由于 Jint 既不生成任何 .NET 字节码也不使用 DLR,因此可以非常快地运行相对较小的脚本
  • 如果重复运行相同的脚本,则应该缓存 Esprima 生成的脚本或模块实例并将其提供给 Jint 而不是内容字符串
  • 更适合在严格模式下运行引擎,可以提高性能
  • Jint 可以适应以下典型场景:

  • 在安全的沙盒环境中在 .NET 应用程序内运行 JavaScript
  • 将本机 .NET 对象和函数公开给 JavaScript 代码,以 JSON 形式获取数据库查询结果、调用 .NET 方法等
  • 支持 .NET 应用程序中的脚本编写,允许用户使用 JavaScript 自定义应用程序(如 Unity 游戏)
  • Jint 的一些用户包括 RavenDB、EventStore、OrchardCore、ELSA Workflows、docfx、JavaScript Engine Switcher 等等。

    目前 Jint 在 Github 通过 BSD-2-Clause 协议开源,有超过 3.7k 的 star,1k 的 fork、1.7k 的项目依赖量,是一个值得关注的开源项目。

    2.如何使用 Jint

    基础示例

    下面示例定义了一个名为 log 的新值,该值指向 Console.WriteLine,然后运行一个调用 log('Hello World!') 的脚本。

    var engine = new Engine() .SetValue("log", new Action<object>(Console.WriteLine));engine.Execute(@" function hello() { log('Hello World'); }; hello();");

    变量 x 设置为 3,并且 x * x 在 JavaScript 中计算。结果直接返回到 .NET,在本例中为双精度值 9。

    var square = new Engine() .SetValue("x", 3) // define a new variable .Evaluate("x * x") // evaluate a statement .ToObject(); // converts the value to .NET

    还可以直接传递 POCO 或匿名对象并从 JavaScript 使用。例如,在此示例中,一个新的 Person 实例是通过 JavaScript 操作的。

    var p = new Person { Name = "Mickey Mouse"};var engine = new Engine() .SetValue("p", p) .Execute("p.Name ='Minnie'");Assert.AreEqual("Minnie", p.Name);

    可以调用 JavaScript 函数引用:

    var add = new Engine() .Execute("function add(a, b) { return a + b; }") .GetValue("add");add.Invoke(1, 2); // -> 3

    或者通过函数名称调用:

    var engine = new Engine() .Execute("function add(a, b) { return a + b; }");engine.Invoke("add", 1, 2); // -> 3

    访问 .NET 程序集和类

    开发者可以通过如下配置引擎实例来允许引擎访问任何 .NET 类:

    var engine = new Engine(cfg => cfg.AllowClr());

    然后就可以将系统命名空间作为全局值进行访问。以下是它在命令行实用程序上下文中的使用方式:

    jint> var file = new System.IO.StreamWriter('log.txt');jint> file.WriteLine('Hello World !');jint> file.Dispose();

    国际化

    如果不想使用计算机的默认值,则可以在使用区域设置 JavaScript 方法时强制引擎应使用的时区或文化,下面示例强制将时区设置为太平洋标准时间。

    var PST = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");var engine = new Engine(cfg => cfg.LocalTimeZone(PST));engine.Execute("new Date().toString()"); // Wed Dec 31 1969 16:00:00 GMT-08:00

    下面示例使用法语作为默认区域性:

    var FR = CultureInfo.GetCultureInfo("fr-FR");var engine = new Engine(cfg => cfg.Culture(FR));engine.Execute("new Number(1.23).toString()"); // 1.23engine.Execute("new Number(1.23).toLocaleString()"); // 1,23

    使用模块

    可以使用模块从多个脚本文件导入和导出变量:

    var engine = new Engine(options =>{ options.EnableModules(@"C:\Scripts");})var ns = engine.Modules.Import("./my-module.js");var value = ns.Get("value").AsString();

    默认情况下,模块解析算法将仅限于 EnableModules 中指定的基本路径,并且没有包支持。但是,开发者可以通过两种方式提供自己的包。 使用 JavaScript 源代码定义模块:

    engine.Modules.Add("user", "export const name ='John';");var ns = engine.Modules.Import("user");var name = ns.Get("name").AsString();

    或者使用模块构建器定义模块,其允许从 .NET 导出 CLR 类和值:

    // Create the module 'lib' with the class My class and the variable versionengine.Modules.Add("lib", builder => builder .ExportType<My class>() .ExportValue("version", 15));// Create a user-defined module and do something with 'lib'engine.Modules.Add("custom", @" import {My class, version} from 'lib'; const x = new My class(); export const result as x.doSomething();");// Import the user-defined module; this will execute the import chainvar ns = engine.Modules.Import("custom");// The result contains "live" bindings to the modulevar id = ns.Get("result").AsInteger();

    3.Jint 的安全性

    以下功能为开发者提供了一个安全的沙盒环境来运行用户脚本:

  • 定义内存限制,以防止分配耗尽内存。
  • 启用 / 禁用 BCL 的使用以防止脚本调用 .NET 代码。
  • 限制语句数量以防止无限循环。
  • 限制调用深度以防止深度递归调用。
  • 定义超时,以防止脚本花费太长时间才能完成。
  • 4.本文总结

    本文主要和大家介绍 Jint ,其是 .NET 的 Javascript 解释器,可以在任何现代 .NET 平台上运行,支持 .NET Standard 2.0 和 .NET 4.6.2 目标(及更高版本)。因为篇幅问题,关于 Jint 主题只是做了一个简短的介绍,但是文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。

    参考资料

    https://github.com/sebastienros/jint

    https://blog.devgenius.io/a-javascript-rules-engine-in-net-6-fb092cdc44c

    https://github.com/topics/jint