Js2Py icon indicating copy to clipboard operation
Js2Py copied to clipboard

Support 'setTimeout' and 'setInterval'

Open amv opened this issue 8 years ago • 4 comments

Currently I get this:

python -c 'import js2py; js2py.eval_js("setTimeout(function() {}, 1 );")'
[....]
js2py.base.PyJsException: ReferenceError: setTimeout is not defined

.. now how hard can implementing the event loop be? ;)

Anyhow, if this is implemented, with browserify one could use for example promise-a-plus to get a working Promise implementation.

amv avatar Jul 09 '17 09:07 amv

You can implement in plain JavaScript. Hold on a moment I will write it now...

PiotrDabkowski avatar Jul 09 '17 10:07 PiotrDabkowski

Okay, here it is:

function __get_event_env__() {
    pyimport time;
    var id = 0;
    var sh = [];
    function add_event(func, args, interval, id) {
        var ev = [func, args, time.time()+interval/1000., id];
        sh.push(ev);
    }
    function clear_event(id) {
        var to_del = false;
        for (var i=0; i<sh.length; i++) {
            if (sh[i][3] === +id) {
                to_del = i;
                break;
            }
        }
        if (to_del !== false) {
            sh.splice(to_del, 1);
        }
    }
    function exec_one() {
        var t = time.time();
        for (var i=0; i<sh.length; i++) {
            if (sh[i][2] <= t) {
                try {
                    sh[i][0].apply(Object(this), sh[i][1]);
                } catch (e) {
                    // todo what should we do in case of errors?
                }
                clear_event(sh[i][3]);
                break
            }
        }
    }
    function setTimeout(func, interval) {
        var args = Array.prototype.slice.call(arguments, 2);
        var my_id = ++id;
        add_event(func, args, interval, my_id);
        return my_id  // todo return a full timeout object
    }
    function setInterval(func, interval) {
        var args = Array.prototype.slice.call(arguments, 2);

        var my_id = ++id;
        function wrap() {
            try {
                func.apply(Object(my_id), args);
            } finally {
                add_event(wrap, [], interval, my_id)
            }
        }
        add_event(wrap, [], interval, my_id);
        return my_id // todo return a full timeout object
    }

    function event_loop() {
        while (true) {
            if (sh.length===0) {
                break
            }
            exec_one();
            time.sleep(0.001);

        }
    }
    function clearInterval(timeoutObj) {
        clear_event(timeoutObj);
    }
    var clearTimeout = clearInterval;
    
    return [setTimeout, clearTimeout, setInterval, clearInterval, event_loop]
}
__event_env__ = __get_event_env__();
var setTimeout = __event_env__[0];
var clearTimeout = __event_env__[1];
var setInterval = __event_env__[2];
var clearInterval = __event_env__[3];
var __event_loop__ = __event_env__[4];

It works but I did not test it properly yet, remember to call __event_loop__ at the end of your program. I still have to implement a proper Timeout object to make it consistent with specs.

PiotrDabkowski avatar Jul 09 '17 11:07 PiotrDabkowski

Well that was fast ;)

I faced some difficulties combining this with the webapp2 framework, where the handler functions are synchronous, and send the response to the client once the function returns, but adding the __event_loop__() call at the end of the handler seemed to work.

I have a feeling that this would make the server non-thread-safe, but as I am continuing this exercise mainly out of academic interest now, I don't think that is a huge problem ;)

I put the current version of the template project on Github if someone else wants to dabble with it in the future too: https://github.com/amv/gae-js2py-es2015-example

amv avatar Jul 10 '17 08:07 amv

@amv I verified this is not thread-safe as you suspected.

@PiotrDabkowski in order for me to be able to use the tool, which I would love, I will need to figure out how to/if we can make it thread-safe.

absynce avatar Oct 26 '20 15:10 absynce