Cache JavaScript Expressions (#5273)
* Add caching for scripts in Jint JavaScript engine A new feature has been implemented to cache the scripts in the Jint JavaScript engine for performance improvement. A new property, "ScriptCacheTimeout", has been introduced to determine the script caching duration. The scripts will be recompiled after the specified duration has elapsed. If the value is null, the scripts will be cached indefinitely. Also, dependencies and changes have been made in the relevant classes to support this feature. * Set default value for ScriptCacheTimeout in JintOptions The change sets a default value for the ScriptCacheTimeout property in the JintOptions.cs file. Previously, ScriptCacheTimeout did not have a default value. Now, ScriptCacheTimeout defaults to one day if no other value is specified. * Refactor JsonSerializerOptions creation in JintJavaScriptEvaluator This change breaks down the creation of JsonSerializerOptions into several lines to improve readability. It also keeps JavaScriptEncoder as the encoder but presents the creation of the object in a more explicit manner.
This commit is contained in:
parent
85ba3fc646
commit
f663ad3813
|
|
@ -1,3 +1,4 @@
|
|||
using Elsa.Caching.Features;
|
||||
using Elsa.Common.Features;
|
||||
using Elsa.Expressions.Features;
|
||||
using Elsa.Extensions;
|
||||
|
|
@ -24,6 +25,7 @@ namespace Elsa.JavaScript.Features;
|
|||
/// </summary>
|
||||
[DependsOn(typeof(MediatorFeature))]
|
||||
[DependsOn(typeof(ExpressionsFeature))]
|
||||
[DependsOn(typeof(MemoryCacheFeature))]
|
||||
public class JavaScriptFeature : FeatureBase
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@ public class JintOptions
|
|||
/// </summary>
|
||||
public bool AllowConfigurationAccess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The timeout for script caching.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <c>ScriptCacheTimeout</c> property specifies the duration for which the scripts are cached in the Jint JavaScript engine. When a script is executed, it is compiled and cached for future use. This caching improves performance by avoiding repetitive compilation of the same script.
|
||||
/// If the value of <c>ScriptCacheTimeout</c> is <c>null</c>, the scripts are cached indefinitely. If a time value is specified, the scripts will be recompiled after the specified duration has elapsed.
|
||||
/// </remarks>
|
||||
public TimeSpan? ScriptCacheTimeout { get; set; } = TimeSpan.FromDays(1);
|
||||
|
||||
/// <summary>
|
||||
/// A list of callbacks that are invoked when the Jint engine is created. Use this to configure the engine.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -12,14 +12,16 @@ using Elsa.JavaScript.Helpers;
|
|||
using Elsa.JavaScript.Notifications;
|
||||
using Elsa.JavaScript.Options;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Esprima;
|
||||
using Esprima.Ast;
|
||||
using Humanizer;
|
||||
using Jint;
|
||||
using Jint.Runtime.Interop;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
// ReSharper disable ConvertClosureToMethodGroup
|
||||
|
||||
namespace Elsa.JavaScript.Services;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -28,15 +30,17 @@ namespace Elsa.JavaScript.Services;
|
|||
public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
||||
{
|
||||
private readonly INotificationSender _mediator;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly JintOptions _jintOptions;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public JintJavaScriptEvaluator(IConfiguration configuration, INotificationSender mediator, IOptions<JintOptions> scriptOptions)
|
||||
public JintJavaScriptEvaluator(IConfiguration configuration, INotificationSender mediator, IOptions<JintOptions> scriptOptions, IMemoryCache memoryCache)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_memoryCache = memoryCache;
|
||||
_jintOptions = scriptOptions.Value;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
|
@ -176,9 +180,21 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
engine.SetValue($"get{outputName}From{activityOutput.ActivityName}", (Func<object?>)(() => context.GetOutput(activityOutput.ActivityId, outputName)));
|
||||
}
|
||||
|
||||
private static object? ExecuteExpressionAndGetResult(Engine engine, string expression)
|
||||
private object? ExecuteExpressionAndGetResult(Engine engine, string expression)
|
||||
{
|
||||
var result = engine.Evaluate(expression);
|
||||
var cacheKey = "jint:script:" + expression.GetHashCode(StringComparison.Ordinal);
|
||||
|
||||
var parsedScript = _memoryCache.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
if (_jintOptions.ScriptCacheTimeout.HasValue)
|
||||
entry.SetAbsoluteExpiration(_jintOptions.ScriptCacheTimeout.Value);
|
||||
|
||||
var parser = new JavaScriptParser(new ParserOptions { AllowReturnOutsideFunction = true });
|
||||
var script = parser.ParseScript(expression);
|
||||
return script;
|
||||
})!;
|
||||
|
||||
var result = engine.Evaluate(parsedScript);
|
||||
return result.ToObject();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue