Search code examples
javascriptc#v8clearscript

Use V8ScriptEngine in C# to re-run script multiple times with different parameters


I have big JavaScript-library that I want to use within my C#-project and it works like a charm using the Microsoft.ClearScript.V8-nuget and the following code:

public int InvokeJavascript(int parameter)
{
    string libraryCode = System.IO.File.ReadAllText("library.js");
    string libraryInvokeCode = $"inoke({parameter})";
    string javascriptCode = $"{libraryCode};{libraryInvokeCode}";
    using (var engine = new V8ScriptEngine())
    {
        var result = engine.Evaluate(javascriptCode);
        return int.Parse(result.ToString());
    }
}

The problem is, that the performance is really poor. I would love to compile the code for the JavaScript Library only once and the invoke on the compiled script to avoid compiling it with every invoke.

Do you have any idea how I can do that?


Solution

  • You're re-reading the library file, re-instantiating the script engine, and re-executing the library code for each call. Caching the engine lets you make multiple calls without all that overhead:

    public sealed class JavaScriptInvoker : IDisposable {
        private V8ScriptEngine _engine = new V8ScriptEngine();
        private string _functionName;
        public JavaScriptInvoker(string libraryCode, string functionName) {
            _engine.Execute(libraryCode);
            _functionName = functionName;
        }
        public object Invoke(params object[] args) => _engine.Invoke(_functionName, args);
        public void Dispose() => _engine.Dispose();
    }
    

    Usage example:

    const string libraryCode = "function invoke(a, b, c) { return a + b + c; }";
    using (var invoker = new JavaScriptInvoker(libraryCode, "invoke")) {
        Console.WriteLine(invoker.Invoke(123, 456, 789));
        Console.WriteLine(invoker.Invoke("foo ", "bar ", "baz"));
    }