4

I´m developing a C# project using JINT (https://github.com/sebastienros/jint), and I need to create a timer on my JS so it can execute a function on my javascript every time the timer tim set is elapsed. How can I accomplish that?. I have used setInterval or setTimeout functions but it seems that they are not part of JINT since it is based on ECMASCRIPT and this functions are not native.

Can someone tell me how I can do this?.

Thanks!!

NicoRiff
  • 4,803
  • 3
  • 25
  • 54
  • There is an extension package that claims to offer just that and more: https://github.com/fredericaltorres/Jint.Ex – djk Jul 20 '17 at 19:05

1 Answers1

10

Neither setInterval and setTimeout are supported by Jint because they are part of the Window API in browsers. with Jint, instead of browser, we have access to CLR, and to be honest it's much more versatile.

First step is to implement our Timer in CLR side, Here is an extremely simple Timer wrapper for built-int System.Threading.Timer class:

namespace JsTools
{
    public class JsTimer
    {
        private Timer _timer;
        private Action _actions;

        public void OnTick(Delegate d)
        {
            _actions += () => d.DynamicInvoke(JsValue.Undefined, new[] { JsValue.Undefined });
        }

        public void Start(int delay, int period)
        {
            if (_timer != null)
                return;

           _timer = new Timer(s => _actions());
           _timer.Change(delay, period);
        }

        public void Stop()
        {
            _timer.Dispose();
            _timer = null;
        }
    }
}

Next step is to bind out JsTimer to Jint engine:

var engine = new Engine(c => c.AllowClr(typeof (JsTimer).Assembly))

Here is an usage example:

internal class Program
{
    private static void Main(string[] args)
    {
        var engine = new Engine(c => c.AllowClr(typeof (JsTimer).Assembly))
            .SetValue("log", new Action<object>(Console.WriteLine))
            .Execute(
                @" 
var callback=function(){
   log('js');
}
var Tools=importNamespace('JsTools');
var t=new Tools.JsTimer();
t.OnTick(callback);
t.Start(0,1000);
");

        Console.ReadKey();
    }
}
user3473830
  • 7,165
  • 5
  • 36
  • 52
  • Thanks Man!!, That worked great!... now I´m looking for something similar to open and close tcp connections... Your example is guiding me to that too!. – NicoRiff Dec 07 '15 at 04:42
  • It works nicely with a single timer. But if I add more than one, `DynamicInvoke` starts randomly crashing with messages like `InvalidOperationException: stack is empty` even when I do nothing inside those callbacks. – JustAMartin Aug 08 '22 at 16:29
  • 1
    @JustAMartin that's probably because Jint is not thread-safe. For both the original `.Execute` (if it can be called from different spots) _and_ the `DynamicInvoke` above, you should use something like a `SemaphoreSlim` (see [here](https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/)) to make sure that only a single thread at a time uses the `Engine`. For me, at least, that fixed the issue. – René van den Berg Sep 13 '22 at 13:25
  • 1
    @RenévandenBerg Right, adding locks fixed the problem; I somehow forgot that Timer calls the actions on different threads from Jint. – JustAMartin Sep 13 '22 at 13:59