
JavaScript Engine Switcher最初是作为辅助库创建的,其开发很大程度上取决于使用它的库的需求。 实际上,每个主要版本都解决了进一步开发其他库所需的一项或多项主要任务:
- 在第一个版本中,此任务是为支持.NET平台的流行JS引擎添加尽可能多的适配器模块。 这为Bundle Transformer用户提供了一定的灵活性:在开发人员的计算机上,他们可以使用支持使用Visual Studio调试JS代码的MSIE模块,在没有现代版本Internet Explorer或根本没有安装Internet Explorer的服务器上,他们可以使用V8模块。 一些人甚至设法使用Jurassic和Jint模块在Linux和Mac上的Mono中运行Bundle Transformer。
- 第二个版本的主要任务是实现.NET Core支持,这是新版本的ReactJS.NET库所必需的 。 另一个重要任务是创建一个跨平台模块,该模块可以快速处理大量JS代码(Jurassic和Jint模块不适合此功能),经过大量改进, ChakraCore模块成为了这样的模块。
- 在第三个版本中,主要重点是改善与ReactJS.NET库的集成并提高生产率。
在本文中,我们将考虑第三版的一些创新,即使阅读了发行文本和文档部分“如何将应用程序升级到3.X版”,对于许多人来说,这些创新仍然是显而易见的: JsEngineSwitcher
类的更改,异常的重组,更多有用的错误消息,中断以及脚本的初步编译,更改ChakraCore和MSIE模块以及基于NiL.JS的新模块的最大堆栈大小的功能。
对JsEngineSwitcher类的更改
在新版本中, JsEngineSwitcher
类实现了IJsEngineSwitcher
接口,并且不再是单例(您可以使用new
运算符实例化它)。 若要获取全局实例,请使用Current
属性而不是Instance
属性。 与不推荐使用的Instance
属性不同, Current
属性的返回类型为IJsEngineSwitcher
。 另外, Current
属性具有一个setter,您可以使用该setter替换标准实现:
JsEngineSwitcher.Current = new MyJsEngineSwitcher();
在安装了JavaScriptEngineSwitcher.Extensions.MsDependencyInjection程序包的ASP.NET Core Web应用程序中,使用AddJsEngineSwitcher
扩展AddJsEngineSwitcher
替换实现:
… using JavaScriptEngineSwitcher.Extensions.MsDependencyInjection; … public class Startup { … public void ConfigureServices(IServiceCollection services) { … services.AddJsEngineSwitcher(new MyJsEngineSwitcher(), options => … ) … ; … } … } …
这些更改几乎总是“破坏”使用旧版JavaScript Engine Switcher的应用程序或库。 因此,您需要对代码进行以下更改:
- 将变量,参数或属性的类型从
JsEngineSwitcher
为IJsEngineSwitcher
。 - 代替
Instance
属性,在任何地方使用Current
属性。
值得注意的是,对于大多数开发人员而言,这些更改不会带来什么好处,因为它们的主要目的是简化单元测试(例如,以前,在ReactJS.NET库的单元测试中,使用了锁,但是现在可以不用它们了 )。
重组例外
在第三个版本之前,大多数JS引擎错误都变成了JsRuntimeException
类型的JsRuntimeException
,只有引擎初始化过程中发生的错误才变成了JsEngineLoadException
。 还有一个基类JsException
,从中继承了上述两种异常类型,这使得绝对可以截获JS引擎运行期间发生的所有错误。 尽管存在明显的缺点,但这种异常组织方式非常适合用于访问JS引擎基本功能的统一接口的概念。
但是随着脚本的中断和预编译的实现(我将在以下各节中讨论它们),需要一种新的组织异常的方法。 首先要做的是添加一种新的异常类型JsInterruptedException
,该异常是通知用户脚本执行中断所必需的。 然后,有必要将脚本处理期间发生的所有错误明确地分为两类:编译错误(分析)和运行时错误。 还需要分离出Chakra和V8的各种特定错误,这些错误与脚本的处理无关。 还必须考虑到Jint引擎中存在异常,该异常是在执行脚本的超时时间(超时)到期时发生的。 结果,形成了一种新的组织异常的方法,可以将其表示为以下层次结构:
JsException
JsEngineException
JsFatalException
JsScriptException
JsCompilationException
JsRuntimeException
JsInterruptedException
JsTimeoutException
JsUsageException
JsEngineNotFoundException
*
*-此异常不会在JS引擎级别发生,而是在JavaScript引擎切换器级别发生。
我认为上述异常的层次结构不需要注释,因为异常的名称可以说明一切。 通过这种方法,我们不仅可以获得有关错误原因的更多信息,而且可以更灵活地处理某些类型的异常。
统一错误消息格式
以前版本的JavaScript Engine Switcher的另一个问题是难以定位在处理脚本时发生的错误。 从Message
异常属性中,很难准确了解代码中错误的发生位置,因此我不得不分析其他异常属性,这并不总是很方便。 此外,现有属性集还不够。
因此,向JsScriptException
类添加了2个新属性:
- Type -JavaScript错误的类型(例如,
SyntaxError
或TypeError
); - DocumentName-文档的名称(通常从以下参数的值中提取:
Execute
和Evaluate
方法的ExecuteFile
, ExecuteFile
方法的path
ExecuteResource
方法的resourceName
等);
一个新属性也已添加到JsRuntimeException
类-CallStack中 ,该属性包含调用堆栈的字符串表示形式。
以前,来自原始.NET异常的相似属性的值或JavaScript错误的字符串表示形式只是被复制到Message
属性中。 通常,不同JS引擎中的错误消息不仅在格式上有所不同,而且在其中呈现的有用信息量也有所不同。 例如,由于某些错误消息中缺少行号和列号信息,因此ReactJS.NET库的开发人员被迫重新抛出从JavaScript Engine Switcher接收到的异常 。
因此,我决定在适配器模块级别生成自己的错误消息,该消息将具有单一(统一)格式。 这种格式使用所有可用的错误信息:类型,描述,文档名称,行号,列号,代码片段和调用堆栈。 作为新格式的基础,我从Microsoft ClearScript库中获取了错误格式。
以下是有关由不同适配器模块生成的相同编译错误的消息:
ChakraCore ========== SyntaxError: Unexpected identifier after numeric literal at declinationOfSeconds.js:12:23 -> caseIndex = number % 1O < 5 ? number % 10 : 5; Jint ==== SyntaxError: Unexpected token ILLEGAL at declinationOfSeconds.js:12:25 Jurassic ======== SyntaxError: Expected operator but found 'O' at declinationOfSeconds.js:12 MSIE Classic ===================== SyntaxError: Expected ';' at declinationOfSeconds.js:12:25 -> caseIndex = number % 1O < 5 ? number % 10 : 5; MSIE Chakra ActiveScript ================================= SyntaxError: Expected ';' at declinationOfSeconds.js:12:25 -> caseIndex = number % 1O < 5 ? number % 10 : 5; MSIE Chakra IE JsRT ============================ SyntaxError: Expected ';' at 12:25 -> caseIndex = number % 1O < 5 ? number % 10 : 5; MSIE Chakra Edge JsRT ============================== SyntaxError: Unexpected identifier after numeric literal at declinationOfSeconds.js:12:23 -> caseIndex = number % 1O < 5 ? number % 10 : 5; NiL === SyntaxError: Unexpected token 'O' at 12:25 V8 == SyntaxError: Invalid or unexpected token at declinationOfSeconds.js:12:24 -> caseIndex = number % 1O < 5 ? number % 10 : 5; Vroom ===== SyntaxError: Unexpected token ILLEGAL at declinationOfSeconds.js:12:24
运行时错误的类似示例:
ChakraCore ========== TypeError: Unable to get property '' of undefined or null reference at transliterate (russian-translit.js:929:4) -> newCharValue = typeof charMapping[charValue] !== 'undefined' ? at Global code (Script Document:1:1) Jint ==== TypeError: charMapping is undefined at russian-translit.js:929:26 Jurassic ======== TypeError: undefined cannot be converted to an object at transliterate (russian-translit.js:929) at Global code (Script Document:1) MSIE Classic ===================== TypeError: 'undefined' is null or not an object at russian-translit.js:929:4 MSIE Chakra ActiveScript ================================= TypeError: Unable to get property '' of undefined or null reference at russian-translit.js:929:4 MSIE Chakra IE JsRT ============================ TypeError: Unable to get property '' of undefined or null reference at transliterate (russian-translit.js:929:4) at Global code (Script Document:1:1) MSIE Chakra Edge JsRT ============================== TypeError: Unable to get property '' of undefined or null reference at transliterate (russian-translit.js:929:4) at Global code (Script Document:1:1) NiL === TypeError: Can't get property "" of "undefined" V8 == TypeError: Cannot read property '' of undefined at transliterate (russian-translit.js:929:37) -> newCharValue = typeof charMapping[charValue] !== 'undefined' ? at Script Document:1:1 Vroom ===== TypeError: Cannot read property '' of undefined at russian-translit.js:929:37
从示例中可以看到,某些JS引擎为我们提供了完全不同的错误描述和列号,我们有时无法始终获得完整的错误数据集,但是尽管有这些缺点,但统一格式为我们提供了有关错误位置的更多信息,而不仅仅是原始错误消息。
本机程序集部署技巧
使用第二版JavaScript Engine Switcher时导致错误的主要原因是,许多开发人员忘记安装包含ChakraCore和V8模块本机程序集的NuGet程序包。 有一次, ReactJS.NET bugtracker中的帖子也专门讨论了这个问题(也提供俄语翻译 )。 现在,这样的错误主要仅发生于由于某种原因而没有阅读文档的初学者。
ReactJS.NET的作者试图使用错误消息中的提示来最小化此类错误的数量,但是这种方法的实施不是很成功,这导致了更多的混乱 。 提示的想法很好,但是它需要一个根本不同的实现,即在JS引擎的适配器模块级别实现。 在新版本的JavaScript Engine Switcher中,将DllNotFoundException
和TypeLoadException
异常包装JsEngineLoadException
时,此类提示会添加到错误消息中(请参阅ChakraCore , V8和Vroom模块的实现示例)。 而且,这些技巧很聪明,因为 它们的生成考虑了许多因素:操作系统类型,处理器体系结构和运行时(.NET Framework,.NET Core或Mono)。
例如,在Windows操作系统上的64位进程中使用不带本地程序集的ChakraCore模块时,错误消息将如下所示:
无法创建ChakraCoreJsEngine的实例。 最有可能发生这种情况,因为未找到“ ChakraCore.dll”程序集或其依赖项之一。 尝试通过NuGet安装JavaScriptEngineSwitcher.ChakraCore.Native.win-x64软件包。 此外,您仍然需要安装适用于Visual Studio 2017的Microsoft Visual C ++ Redistributable( https://www.visualstudio.com/downloads/#microsoft-visual-c-redistributable-for-visual-studio-2017 )。
该错误消息提示您需要安装JavaScript NuGet程序包EngineSwitcher.ChakraCore.Native.win-x64,并且还提到Windows的ChakraCore需要Microsoft Visual C ++可再发行组件才能使Visual Studio 2017正常工作。如果发生在32位进程中,则将要求用户安装JavaScriptEngineSwitcher.ChakraCore.Native.win-x86软件包。
在.NET Core中的Linux上,类似的错误消息如下所示:
无法创建ChakraCoreJsEngine的实例。 最有可能发生这种情况,因为未找到“ libChakraCore.so”程序集或其依赖项之一。 尝试通过NuGet安装JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64软件包。
在这种情况下,建议安装JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64软件包。
在Mono中启动时,将显示另一个提示:
... JavaScriptEngineSwitcher.ChakraCore.Native.linux- *软件包不支持在Mono下安装,但是您可以手动安装本机程序集( https://github.com/Taritsyn/JavaScriptEngineSwitcher/wiki/ChakraCore#linux )。
由于JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64软件包仅与.NET Core兼容,因此工具提示将提供指向有关在Linux上手动部署本机程序集的说明的链接。
可以给出更多示例,但这没有任何意义。
中止脚本执行
当我们为用户提供在服务器上执行任意JS代码的机会时,我们面临一个非常严重的问题-我们不知道执行此代码需要花费多长时间。 这可能是大量的非最佳代码或运行无限循环的代码。 无论如何,它将是不受控制的代码,它将无限期地消耗我们服务器的资源。 为了以某种方式控制此过程,我们需要能够中断脚本的执行。 使用纯.NET编写的引擎(例如Jint,Jurassic或NiL.JS)时,我们始终可以将具有取消功能的JS代码作为一个任务开始执行,但是这种方法不适用于其他引擎。 对我们来说幸运的是,C ++引擎具有用于中断脚本的内置机制。
为了提供对这些机制的访问,将SupportsScriptInterruption
属性和Interrupt
方法添加到了IJsEngine
接口。 由于并非所有引擎都支持此功能,因此在调用Interrupt
方法之前,应始终检查SupportsScriptInterruption
属性的值(如果在JavaScript Engine Switcher的早期版本中必须手动运行垃圾收集器,您将立即了解我在说什么):
if (engine.SupportsScriptInterruption) { engine.Interrupt(); }
并且您需要在与执行脚本的线程不同的单独线程中调用此方法。 调用Interrupt
方法后,所有先前运行的Evaluate
, Execute*
和CallFunction
都将以JsInterruptedException
。
由于此API是低级的,因此对于本节开头所述的任务,建议使用以下扩展方法:
using System; #if !NET40 using System.Runtime.ExceptionServices; #endif using System.Threading; using System.Threading.Tasks; using JavaScriptEngineSwitcher.Core; #if NET40 using JavaScriptEngineSwitcher.Core.Extensions; #endif using JavaScriptEngineSwitcher.Core.Resources; … /// <summary> /// Extension methods for <see cref="IJsEngine"/> /// </summary> public static class JsEngineExtensions { /// <summary> /// Evaluates an expression within a specified time interval /// </summary> /// <typeparam name="T">Type of result</typeparam> /// <param name="engine">JS engine</param> /// <param name="expression">JS expression</param> /// <param name="timeoutInterval">Interval to wait before the /// script execution times out</param> /// <param name="documentName">Document name</param> /// <returns>Result of the expression</returns> /// <exception cref="ObjectDisposedException"/> /// <exception cref="ArgumentNullException"/> /// <exception cref="ArgumentException"/> /// <exception cref="JsCompilationException"/> /// <exception cref="JsTimeoutException"/> /// <exception cref="JsRuntimeException"/> /// <exception cref="JsException"/> public static T Evaluate<T>(this IJsEngine engine, string expression, TimeSpan timeoutInterval, string documentName) { if (engine == null) { throw new ArgumentNullException(nameof(engine)); } if (engine.SupportsScriptInterruption) { using (var timer = new Timer(state => engine.Interrupt(), null, timeoutInterval, #if NET40 new TimeSpan(0, 0, 0, 0, -1))) #else Timeout.InfiniteTimeSpan)) #endif { try { return engine.Evaluate<T>(expression, documentName); } catch (JsInterruptedException e) { throw new JsTimeoutException( Strings.Runtime_ScriptTimeoutExceeded, e.EngineName, e.EngineVersion, e ); } } } else { #if NET40 Task<T> task = Task.Factory.StartNew(() => #else Task<T> task = Task.Run(() => #endif { return engine.Evaluate<T>(expression, documentName); }); bool isCompletedSuccessfully = false; try { isCompletedSuccessfully = task.Wait(timeoutInterval); } catch (AggregateException e) { Exception innerException = e.InnerException; if (innerException != null) { #if NET40 innerException.PreserveStackTrace(); throw innerException; #else ExceptionDispatchInfo.Capture(innerException).Throw(); #endif } else { throw; } } if (isCompletedSuccessfully) { return task.Result; } else { throw new JsTimeoutException( Strings.Runtime_ScriptTimeoutExceeded, engine.Name, engine.Version ); } } } … } …
此方法是引擎方法Evaluate<T>
的附加组件,该方法允许使用timeoutInterval
参数设置等待脚本执行的超时。 这种扩展方法的操作原理非常简单。 首先,我们检查引擎是否支持内置的中断机制。 如果是timeoutInterval
,我们将创建一个Timer
类的实例,该实例在timeoutInterval
参数指定的timeoutInterval
间隔后启动Interrupt
方法,然后调用Evaluate<T>
引擎方法,如果发生错误,则捕获JsInterruptedException
并将其包装在JsTimeoutException
。 如果引擎不支持中断,则创建运行引擎的Evaluate<T>
方法的Task
类的实例,然后将要执行的任务的等待间隔设置为与timeoutInterval
参数中的值相等,如果任务在超时之前完成,则抛出JsTimeoutException
类型JsTimeoutException
。 以下是使用此扩展方法的示例:
using System; … using JavaScriptEngineSwitcher.Core; using JavaScriptEngineSwitcher.Core.Helpers; … class Program { … static void Main(string[] args) { const string expression = @"function getRandomInt(minValue, maxValue) { minValue = Math.ceil(minValue); maxValue = Math.floor(maxValue); return Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue; } function sleep(millisecondsTimeout) { var totalMilliseconds = new Date().getTime() + millisecondsTimeout; while (new Date().getTime() < totalMilliseconds) { } } var randomNumber = getRandomInt(1, 10); sleep(randomNumber * 1000); randomNumber;"; using (IJsEngine engine = JsEngineSwitcher.Current.CreateDefaultEngine()) { try { int result = engine.Evaluate<int>(expression, TimeSpan.FromSeconds(3), "randomNumber.js"); Console.WriteLine(" = {0}", result); } catch (JsTimeoutException) { Console.WriteLine(" JavaScript " + " !"); } catch (JsException e) { Console.WriteLine(" JavaScript- " + "!"); Console.WriteLine(); Console.WriteLine(JsErrorHelpers.GenerateErrorDetails(e)); } } } … } …
使用扩展方法,我们计算JS表达式的结果。 表达式的结果是一个随机整数,该数字也是该表达式延迟的秒数。 另外,在调用扩展方法时,我们指定3秒的等待间隔。 由于计算表达式的时间在1到10秒之间变化,因此在一种情况下,表达式的结果将显示在控制台上,而在另一种情况下,则显示有关超时的消息。
重新CallFunction
此扩展方法以调用其他引擎方法(例如,对Execute*
, CallFunction
或Evaluate
方法的其他重载版本)应该并不困难。 到目前为止,我尚未决定是否将此类扩展方法添加到库本身,因为目前尚不清楚它们将需要多少。
脚本预编译
我被要求在2015年增加对脚本的初步编译的支持。 当时还不清楚这种功能如何适合统一接口的概念。 但是随着时间的流逝,JavaScript引擎切换器开始逐渐出现了对诸如垃圾收集和脚本中断之类的可访问性功能的支持。 在第三版工作的最后阶段,转向初步编译。
使用预编译,您可以编译一次脚本,然后多次使用它来初始化JS引擎。 由于预编译脚本不需要解析,因此引擎的初始化会更快。
当前,预编译由5个适配器模块支持:ChakraCore,Jint,Jurassic,MSIE(仅在JsRT模式下)和V8。 为了提供对相应引擎机制的访问,在IJsEngine
接口中添加了SupportsScriptPrecompilation
属性和3个新方法: Precompile
, PrecompileFile
和PrecompileResource
。 Precompile*
方法返回实现IPrecompiledScript
接口的对象的实例。 该对象是可以由引擎的不同实例使用的预编译脚本(为此目的, Execute
方法的重载版本)。 考虑一个使用此API的简单示例:
using System; … using JavaScriptEngineSwitcher.Core; using JavaScriptEngineSwitcher.Core.Helpers; … class Program { … static void Main(string[] args) { const string sourceCode = @"function declinationOfSeconds(number) { var result, titles = ['', '', ''], titleIndex, cases = [2, 0, 1, 1, 1, 2], caseIndex ; if (number % 100 > 4 && number % 100 < 20) { titleIndex = 2; } else { caseIndex = number % 10 < 5 ? number % 10 : 5; titleIndex = cases[caseIndex]; } result = number + ' ' + titles[titleIndex]; return result; }"; const string functionName = "declinationOfSeconds"; const int itemCount = 4; int[] inputSeconds = new int[itemCount] { 0, 1, 42, 600 }; string[] outputStrings = new string[itemCount]; IJsEngineSwitcher engineSwitcher = JsEngineSwitcher.Current; IPrecompiledScript precompiledCode = null; using (var engine = engineSwitcher.CreateDefaultEngine()) { if (!engine.SupportsScriptPrecompilation) { Console.WriteLine("{0} {1} " + " !", engine.Name, engine.Version); return; } try { precompiledCode = engine.Precompile(sourceCode, "declinationOfSeconds.js"); engine.Execute(precompiledCode); outputStrings[0] = engine.CallFunction<string>(functionName, inputSeconds[0]); } catch (JsCompilationException e) { Console.WriteLine(" " + " !"); Console.WriteLine(); Console.WriteLine(JsErrorHelpers.GenerateErrorDetails(e)); return; } catch (JsException e) { Console.WriteLine(" JavaScript- " + "!"); Console.WriteLine(); Console.WriteLine(JsErrorHelpers.GenerateErrorDetails(e)); return; } } for (int itemIndex = 1; itemIndex < itemCount; itemIndex++) { using (var engine = engineSwitcher.CreateDefaultEngine()) { try { engine.Execute(precompiledCode); outputStrings[itemIndex] = engine.CallFunction<string>( functionName, inputSeconds[itemIndex]); } catch (JsException e) { Console.WriteLine(" JavaScript- " + " !"); Console.WriteLine(); Console.WriteLine(JsErrorHelpers.GenerateErrorDetails(e)); return; } } } for (int itemIndex = 0; itemIndex < itemCount; itemIndex++) { Console.WriteLine(outputStrings[itemIndex]); } } … } …
, . SupportsScriptPrecompilation
, , , . Precompile
, , JsCompilationException
. C Execute
, .. . CallFunction
declinationOfSeconds
. . , , . 3 . , , . , , .
, , . , , . ReactJS.NET. JSPool , ( System.Runtime.Caching.MemoryCache
.NET Framework 4.X, System.Web.Caching.Cache
ASP.NET 4.X Microsoft.Extensions.Caching.Memory.IMemoryCache
ASP.NET Core). , ( ). , ReactJS.NET.
ReactJS.NET . . AllowJavaScriptPrecompilation
true
.
ASP.NET 4.X App_Start/ReactConfig.cs
:
… public static class ReactConfig { public static void Configure() { ReactSiteConfiguration.Configuration … .SetAllowJavaScriptPrecompilation(true) … ; … } } …
ASP.NET Core Startup.cs
:
… public class Startup { … public void Configure(IApplicationBuilder app, IHostingEnvironment env) { … app.UseReact(config => { config … .SetAllowJavaScriptPrecompilation(true) … ; }); app.UseStaticFiles(); … } } …
, . JsExecutionBenchmark , BenchmarkDotNet . JS- . 14,9 , , . JavaScript Engine Switcher ( 3.0.4).
, .NET Framework 4.7.2:
| . | . | Gen 0 . . | Gen 1 . . | Gen 2 . . | . |
---|
ChakraCore | | 41,72 | - | - | - | 74,46 |
| 35,07 | - | - | - | 91,79 |
Jint | | 27,19 | 2 812,50 | 1 343,75 | - | 16 374,58 |
| 15,54 | 1 296,88 | 640,63 | 31,25 | 7 521,49 |
Jurassic | | 455,70 | 2 000,00 | 1 000,00 | - | 15 575,28 |
| 78,70 | 1 000,00 | - | - | 7 892,94 |
MSIE Chakra IE JsRT | | 30,97 | - | - | - | 77,75 |
| 24,40 | - | - | - | 90,58 |
MSIE Chakra Edge JsRT | | 33,14 | - | - | - | 78,40 |
| 32,86 | - | - | - | 95,48 |
V8 | | 41,10 | - | - | - | 79,33 |
| 39,25 | - | - | - | 96,17 |
, .NET — Jurassic 5,79 , Jint 1,75 a. 2 , 2 . . Jurassic, : Jurassic JS- IL- Reflection.Emit, . , , . Jint .NET-, . Jint , . , Jint , , . Jint Jurassic .
, C++, MSIE Chakra IE JsRT — 26,93%. ChakraCore (18,96%), V8 (4,71%) MSIE Chakra Edge JsRT (0,85%). Internet Explorer Edge. . ( ) . , - 12-17 ( ). . . .
.NET Core 2.0 ( V8 , Microsoft ClearScript, , .NET Core):
| . | . | Gen 0 . . | Gen 1 . . | Gen 2 . . | . |
---|
ChakraCore | | 43,65 | - | - | - | 18,07 |
| 36,37 | - | - | - | 16,59 |
Jint | | 24,87 | 2 750,00 | 1 375,00 | - | 16 300,25 |
| 15,25 | 1 281,25 | 593,75 | 62,50 | 7 447,44 |
Jurassic | | 469,97 | 2 000,00 | 1 000,00 | - | 15 511,70 |
| 80,72 | 1 000,00 | - | - | 7 845,98 |
MSIE Chakra IE JsRT | | 31,50 | - | - | - | 20,28 |
| 24,52 | - | - | - | 18,78 |
MSIE Chakra Edge JsRT | | 35,54 | - | - | - | 20,45 |
| 31,44 | - | - | - | 18,99 |
. , — MSIE Chakra Edge JsRT (7,69%). Chakra .
ChakraCore MSIE
, Microsoft, , . IIS (256 32- 512 64-), ASP.NET JS- (, TypeScript) . JavaScript Engine Switcher . , Node.js (492 32- 984 64-). , , - . ChakraCore MSIE MaxStackSize
, . Node.js. , .
NiL.JS
- NiL , NiL.JS . NiL.JS — JS-, .NET. 2014 , Jurassic Jint. — . , .
.NET Framework 4.7.2 :
| . | Gen 0 . . | Gen 1 . . | Gen 2 . . | . |
---|
Jint | 27,19 | 2 812,50 | 1 343,75 | - | 16 374,58 |
Jurassic | 455,70 | 2 000,00 | 1 000,00 | - | 15 575,28 |
NiL | 17,80 | 1 000,00 | - | - | 4 424,09 |
.NET Core 2.0 :
| . | Gen 0 . . | Gen 1 . . | Gen 2 . . | . |
---|
Jint | 24,87 | 2 750,00 | 1 375,00 | - | 16 300,25 |
Jurassic | 469,97 | 2 000,00 | 1 000,00 | - | 15 511,70 |
NiL | 19,67 | 1 000,00 | - | - | 4 419,95 |
. , ( ). , Jint 2016 , . 3.0.0 Beta 1353 , Jint 2,4 , NiL.JS 2.5.1200, .
NiL.JS . - , - , . Bundle Transformer, JavaScript Engine Switcher, Hogan Handlebars, ReactJS.NET. NiL.JS.
参考文献
- JavaScript Engine Switcher GitHub
- JavaScript Engine Switcher
- « JavaScript Engine Switcher 2.X»
- JSPool GitHub
- ReactJS.NET
- ReactJS.NET GitHub