JavaScript Engine Switcher was originally created as a supporting library and its development was largely determined by the needs of the libraries that used it. In fact, each major version of it solved one or several major tasks necessary for the further development of other libraries:
In this article, we will look at some of the innovations of the third version, which for many turned out to be not obvious even after reading the release text and the βHow to upgrade applications to version 3.Xβ section of the documentation: changes in the JsEngineSwitcher
class, reorganization of exceptions, more informative error messages, interruption and pre-compiling scripts, the ability to change the maximum stack size in the modules ChakraCore and MSIE, as well as a new module based on NiL.JS.
In the new version, the JsEngineSwitcher
class implements the IJsEngineSwitcher
interface and is no longer a singleton (its instance can be created using the new
operator). To get a global instance, use the Current
property instead of the Instance
property. The Current
property, unlike the obsolete Instance
property, has the return type IJsEngineSwitcher
. Also, the Current
property has a setter, with which you can replace the standard implementation with your own:
JsEngineSwitcher.Current = new MyJsEngineSwitcher();
In ASP.NET Core web applications where the JavaScriptEngineSwitcher.Extensions.MsDependencyInjection package is installed, the implementation is replaced using the AddJsEngineSwitcher
extension AddJsEngineSwitcher
:
β¦ using JavaScriptEngineSwitcher.Extensions.MsDependencyInjection; β¦ public class Startup { β¦ public void ConfigureServices(IServiceCollection services) { β¦ services.AddJsEngineSwitcher(new MyJsEngineSwitcher(), options => β¦ ) β¦ ; β¦ } β¦ } β¦
These changes almost always βbreakβ applications or libraries that use the previous version of JavaScript Engine Switcher. Therefore, you need to make the following changes to your code:
JsEngineSwitcher
to IJsEngineSwitcher
.Instance
property, use the Current
property everywhere.It is also worth noting that for most developers, these changes will not be particularly useful, because their main goal was to simplify unit tests (for example, blocking was used in the unit tests of the ReactJS.NET library, and now you can do without them ).
Prior to the third version, most of the errors of JS engines turned into exceptions of the JsRuntimeException
type, and only errors that occurred during the engine initialization process turned into a JsEngineLoadException
. There was also a base class JsException
, from which the two types of exceptions listed above inherited, which allowed to intercept absolutely all the errors that occurred during the work of JS engines. Despite obvious shortcomings, such an organization of exceptions fit well into the concept of a unified interface for accessing the basic features of JS engines.
But when realizing the possibilities of interruption and preliminary compilation of scripts (I will talk about them in the next sections), a need arose for a new approach to the organization of exceptions. The first thing to do was to add a new exception type - JsInterruptedException
, which was necessary to notify the user about the interruption of script execution. Then it was necessary to explicitly divide all errors that occurred while processing scripts into two groups: compilation errors (syntax analysis) and runtime errors. Also required to separate all sorts of specific errors Chakra and V8, which were not associated with the processing of scripts. It was also necessary to take into account the presence in the Jint engine of an exception that occurs when the script execution timeout (timeout) expires. As a result, a new approach to the organization of exceptions was formed, which can be represented as the following hierarchical structure:
JsException
JsEngineException
JsEngineLoadException
JsFatalException
JsScriptException
JsCompilationException
JsRuntimeException
JsInterruptedException
JsTimeoutException
JsUsageException
JsEngineNotFoundException
** - this exception occurs not at the level of the JS engine, but at the level of JavaScript Engine Switcher.
I think that the hierarchy of exceptions presented above does not need comments, because the names of the exceptions speak for themselves. With this approach, we get not only more information about the causes of the error, but we can more flexibly handle certain types of exceptions.
Another problem with previous versions of JavaScript Engine Switcher was the difficulty in locating errors that occurred during script processing. It was difficult to understand exactly where the error occurred from the Message
exception property, so we had to analyze other exception properties, which was not always convenient. In addition, a set of existing properties was also insufficient.
Therefore, 2 new properties have been added to the JsScriptException
class:
SyntaxError
or TypeError
);documentName
of the Execute
and Evaluate
methods, path
the ExecuteFile
method, resourceName
the ExecuteResource
method, etc.);One new property has also been added to the JsRuntimeException
class - CallStack , which contains a string representation of the call stack.
Previously, the Message
property simply copied a value from a similar property of the original .NET exception or a string representation of a JavaScript error. Often, error messages in different JS engines differed not only in the format, but also in the amount of useful information presented in them. For example, due to the lack of information about the row and column numbers in some error messages, the developers of the ReactJS.NET library were forced to override the exceptions obtained from the JavaScript Engine Switcher.
Therefore, I decided to generate my own error messages at the level of adapter modules that would have a single (unified) format. This format uses all available error information: type, description, document name, line number, column number, code fragment, and call stack. As a basis for the new format, I took the error format from the Microsoft ClearScript library.
Below are the messages about the same compilation error that were generated by different adapter modules:
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
A similar example for a runtime error:
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
From the examples it can be seen that some JS engines give us completely different error descriptions and column numbers, and not always we can get a complete set of error data, but even despite these shortcomings, the unified format gives us more information about the location of the error than original error messages.
The main cause of errors when working with the second version of JavaScript Engine Switcher was that many developers forgot to install NuGet packages containing native assemblies for ChakraCore and V8 modules. At one time, this post was even devoted to a post in the ReactJS.NET bugtracker (a Russian translation is also available). Now, this is mostly a bug for newbies who, for some reason, have not read the documentation.
The authors of ReactJS.NET tried to minimize the number of such errors with the help of hints inside error messages, but the not very successful implementation of this approach led to even more confusion . The idea of ββthe prompts was good, but it required a fundamentally different implementation, namely, the implementation of JS engines at the level of adapter modules. In the new version of JavaScript Engine Switcher, such hints are added to the error message when wrapping DllNotFoundException
and TypeLoadException
exceptions into a JsEngineLoadException
exception (see the implementation examples for ChakraCore , V8, and Vroom modules). Moreover, these tips are intelligent, because their generation takes into account a number of factors: the type of operating system, processor architecture and runtime (.NET Framework, .NET Core or Mono).
For example, if you use the ChakraCore module without a native build in a 64-bit process on the Windows operating system, the error message will look like this:
Failed to create an instance of the ChakraCoreJsEngine. Most likely it happened, because the dependencies were not found. Try to install the JavaScriptEngineSwitcher.ChakraCore.Native.win-x64 package via NuGet. In addition, you still need to install the Microsoft Visual C ++ Redistributable for Visual Studio 2017 ( https://www.visualstudio.com/downloads/#microsoft-visual-c-redistributable-for-visual-studio-2017 ).
The error message prompts you to install the NuGet package JavaScriptEngineSwitcher.ChakraCore.Native.win-x64, and also mentions that ChakraCore for Windows requires a Microsoft Visual C ++ redistributable component for Visual Studio 2017 to work. If this error will occur in a 32-bit process, the user will be prompted to install the JavaScriptEngineSwitcher.ChakraCore.Native.win-x86 package.
A similar error message on Linux in the .NET Core environment will look like this:
Failed to create an instance of the ChakraCoreJsEngine. Most likely it happened, because of its dependencies was not found. Try to install the JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64 package via NuGet.
In this case, you will be prompted to install the JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64 package.
When launched in Mono, another hint will be displayed:
... JavaScriptEngineSwitcher.ChakraCore.Native.linux- * package
Since the JavaScriptEngineSwitcher.ChakraCore.Native.linux-x64 package is only compatible with .NET Core, the prompt will link to instructions for manually deploying the native build in Linux.
You can still give many examples, but this makes no sense.
When we give users the ability to execute arbitrary JS code on the server, we face one very serious problem - we donβt know how long it will take to execute this code. This may be a large amount of non-optimal code or a code that starts an infinite loop. In any case, this will be code that we cannot control, which will consume our server resources indefinitely. In order to somehow control this process, we need the ability to interrupt the execution of scripts. When using engines written in pure .NET (for example, Jint, Jurassic or NiL.JS), we can always start executing JS-code as a task with the possibility of cancellation, but this approach will not work for other engines. Fortunately for us, the engines written in C ++ have built-in mechanisms for interrupting scripts.
To provide access to these mechanisms, the SupportsScriptInterruption
property and the Interrupt
method IJsEngine
been added to the IJsEngine
interface. Since not all engines support this feature, you should always check the value of the SupportsScriptInterruption
property before calling the Interrupt
method (if you had to manually start the garbage collector in previous versions of JavaScript Engine Switcher, you will immediately understand what I am talking about):
if (engine.SupportsScriptInterruption) { engine.Interrupt(); }
Moreover, it is necessary to call this method in a separate thread other than the one in which the scripts are executed. After calling the Interrupt
method, all previously run Evaluate
, Execute*
and CallFunction
will be completed by throwing a JsInterruptedException
exception.
Since this API is low-level, for the tasks described in the beginning of the section it is recommended to use extension methods like this:
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 ); } } } β¦ } β¦
This method is an add-on over the Evaluate<T>
engine method, which allows setting the timeout for the script execution using the timeoutInterval
parameter. The principle of this extension method is very simple. First, we check if our engine supports the built-in interrupt mechanism. If it timeoutInterval
, then we create an instance of the Timer
class, which, through the timeoutInterval
parameter, starts the Interrupt
method, then we call the Evaluate<T>
engine method, and in case of an error, we catch the JsInterruptedException
exception and wrap it in a JsTimeoutException
. If the engine does not support interrupts, then create an instance of the Task
class that runs the Evaluate<T>
engine method, then set the task timeout interval equal to the value from the timeoutInterval
parameter, and if the task timed out, then throw an exception of type JsTimeoutException
. The following is an example of using this extension method:
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)); } } } β¦ } β¦
Using the extension method, we calculate the result of a JS expression. The result of the expression is a random integer, and this number is also the number of seconds by which the execution of this expression is delayed. Also, when calling the extension method, we specify a wait interval of 3 seconds. Since the time to calculate the expression varies from 1 to 10 seconds, in one case the result of the expression will be displayed on the console, and in the other the message about waiting time is displayed.
It should be easy for you to remake this extension method to call other methods of the engine (for example, under the Execute*
, CallFunction
or other overloaded versions of the Evaluate
method). While I have not yet decided whether I will add such extension methods to the library itself, because it is not yet clear how much they will be in demand.
I was asked to add support for pre-compiling scripts back in 2015 . At that moment, it was not clear how such a function could fit into the concept of a unified interface. But as time went on, support for special features such as garbage collection and script interruption began to appear in JavaScript Engine Switcher. At the last stages of work on the third version, the turn reached the preliminary compilation.
Using precompilation, you can compile the script once, and then use it many times to initialize the JS engines. Due to the fact that the pre-compiled script does not require syntactic analysis, the initialization of the engines will be faster.
At the moment, 5 modules-adapters support preliminary compilation: ChakraCore, Jint, Jurassic, MSIE (only in JsRT-modes) and V8. To provide access to the corresponding engine mechanisms, the SupportsScriptPrecompilation
property and 3 new methods were added to the IJsEngine
interface: Precompile
, PrecompileFile
and PrecompileResource
. Precompile*
methods return an instance of an object that implements the IPrecompiledScript
interface. This object is a pre-compiled script that can be used by different instances of engines (for these purposes serves as an overloaded version of the Execute
method). Consider a simple example of using this 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 | Not | 41,72 ΠΌΡ | - | - | - | 74,46 ΠΠ± |
Yes | 35,07 ΠΌΡ | - | - | - | 91,79 ΠΠ± | |
Jint | Not | 27,19 ΠΌΡ | 2 812,50 | 1 343,75 | - | 16 374,58 ΠΠ± |
Yes | 15,54 ΠΌΡ | 1 296,88 | 640,63 | 31,25 | 7 521,49 ΠΠ± | |
Jurassic | Not | 455,70 ΠΌΡ | 2 000,00 | 1 000,00 | - | 15 575,28 ΠΠ± |
Yes | 78,70 ΠΌΡ | 1 000,00 | - | - | 7 892,94 ΠΠ± | |
MSIE Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ Chakra IE JsRT | Not | 30,97 ΠΌΡ | - | - | - | 77,75 ΠΠ± |
Yes | 24,40 ΠΌΡ | - | - | - | 90,58 ΠΠ± | |
MSIE Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ Chakra Edge JsRT | Not | 33,14 ΠΌΡ | - | - | - | 78,40 ΠΠ± |
Yes | 32,86 ΠΌΡ | - | - | - | 95,48 ΠΠ± | |
V8 | Not | 41,10 ΠΌΡ | - | - | - | 79,33 ΠΠ± |
Yes | 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 | Not | 43,65 ΠΌΡ | - | - | - | 18,07 ΠΠ± |
Yes | 36,37 ΠΌΡ | - | - | - | 16,59 ΠΠ± | |
Jint | Not | 24,87 ΠΌΡ | 2 750,00 | 1 375,00 | - | 16 300,25 ΠΠ± |
Yes | 15,25 ΠΌΡ | 1 281,25 | 593,75 | 62,50 | 7 447,44 ΠΠ± | |
Jurassic | Not | 469,97 ΠΌΡ | 2 000,00 | 1 000,00 | - | 15 511,70 ΠΠ± |
Yes | 80,72 ΠΌΡ | 1 000,00 | - | - | 7 845,98 ΠΠ± | |
MSIE Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ Chakra IE JsRT | Not | 31,50 ΠΌΡ | - | - | - | 20,28 ΠΠ± |
Yes | 24,52 ΠΌΡ | - | - | - | 18,78 ΠΠ± | |
MSIE Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ Chakra Edge JsRT | Not | 35,54 ΠΌΡ | - | - | - | 20,45 ΠΠ± |
Yes | 31,44 ΠΌΡ | - | - | - | 18,99 ΠΠ± |
Π ΡΠ΅Π»ΠΎΠΌ ΠΌΡ ΠΏΠΎΠ»ΡΡΠΈΠ»ΠΈ ΠΏΠΎΡ ΠΎΠΆΠΈΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ. ΠΠ΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΠΎΠ΅, ΡΡΠΎ Π±ΡΠΎΡΠ°Π΅ΡΡΡ Π² Π³Π»Π°Π·Π° β ΡΠ΅Π·ΡΠ»ΡΡΠ°Ρ MSIE Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ Chakra Edge JsRT ΡΠ»ΡΡΡΠΈΠ»ΡΡ (7,69%). Π’Π°ΠΊΠΆΠ΅ Π² Π΄Π°Π½Π½ΠΎΠΌ ΡΠ»ΡΡΠ°Π΅ ΠΏΡΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠΈ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎΠΉ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ Π΄Π²ΠΈΠΆΠΊΠ°ΠΌΠΈ ΡΠ΅ΠΌΠ΅ΠΉΡΡΠ²Π° Chakra ΡΠ½ΠΈΠΆΠ°Π΅ΡΡΡ ΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΠ΅ ΡΠΏΡΠ°Π²Π»ΡΠ΅ΠΌΠΎΠΉ ΠΏΠ°ΠΌΡΡΠΈ.
Π Π°Π·ΠΌΠ΅Ρ ΡΡΠ΅ΠΊΠ° Π² Π΄Π²ΠΈΠΆΠΊΠ°Ρ
, ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ°Π½Π½ΡΡ
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 , ΠΊΠΎΡΠΎΡΡΠΉ ΡΠΎΠ·Π΄Π°Π½ Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ Π΄Π²ΠΈΠΆΠΊΠ° 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.
Source: https://habr.com/ru/post/439446/