如何在JINT JavaScript端创建定时器

4
我正在使用JINT (https://github.com/sebastienros/jint) 开发一个C#项目,需要在我的JS中创建一个计时器,以便每当定时器到期时,它可以执行我的javascript函数。我该如何实现? 我已经尝试了setInterval或setTimeout函数,但它们似乎不是JINT的一部分,因为它基于ECMASCRIPT,而这些函数不是原生的。请问有人可以告诉我如何做吗? 谢谢!

有一个扩展包声称可以提供这个功能以及更多功能: https://github.com/fredericaltorres/Jint.Ex - djk
1个回答

10

由于 setIntervalsetTimeout 是浏览器中的 Window API 的一部分,因此 Jint 不支持它们。使用 Jint,我们可以访问 CLR 而不是浏览器,而且说实话更加通用。

第一步是在 CLR 端实现我们的计时器,在此处提供了一个极其简单的 Timer 包装器,用于内置的 System.Threading.Timer 类:

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;
        }
    }
}

下一步是将 JsTimer 绑定到 Jint 引擎:
var engine = new Engine(c => c.AllowClr(typeof (JsTimer).Assembly))

以下是一个使用示例:
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();
    }
}

谢谢,太棒了!现在我正在寻找类似于打开和关闭TCP连接的东西...你的例子也指引着我去做这件事! - NicoRiff
它在单个计时器上运行得很好。但是如果我添加多个计时器,即使在这些回调函数中什么也不做,DynamicInvoke 也会随机崩溃,并显示诸如 InvalidOperationException: stack is empty 的消息。 - JustAMartin
1
@JustAMartin 这可能是因为 Jint 不是线程安全的。对于原始的 .Execute(如果可以从不同的位置调用)和上面的 DynamicInvoke,您应该使用类似于 SemaphoreSlim 的东西(请参见这里),以确保只有一个线程在任何时候使用 Engine。对我来说,至少这解决了问题。 - René van den Berg
1
@RenévandenBerg 好的,添加锁定解决了问题;我不知怎么忘记了Timer在不同线程上调用操作而不是Jint。 - JustAMartin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接