-1

Let's say I have a long-running JavaScript process that can be started by clicking a button. Once it runs, it freezes the browser. The process consists of a long loop that repeats some workload where one iteration takes comparatively little time. Here is a stripped down version of such a 'loop-like' process:

<html>

<head>
    <script>
        var Process = function(start) {
            this.start = start;
        }

        Process.prototype.run = function(stop) {
            // Long-running loop
            for (var i = this.start; i < stop; i++) {
                // Inside the loop there is some workload which 
                // is the code that is to be debugged
                console.log(i);
            }
        }

        var p = new Process(100);

        window.onload = function() {
            document.getElementById("start").onclick = function() {
                p.run(1000000000);
            }
        }
    </script>
</head>

<body>
    <input id="start" type="button" value="Start" />
</body>

</html>

Due to the browser freeze, debugging a loop-like script is not easy. One alternative to avoid browser freeze is using a web worker. The drawback of that approach is the poor debuggabilty of web workers: Tools like Firebug are not supported.

Is there a way to avoid browser freeze while maintaining debuggabilty? If yes, the script could be debugged until it is stable and delegated to a web worker for production.

chessweb
  • 4,613
  • 5
  • 27
  • 32
  • I'm not sure this, you answered your question, that's good, but the interval between you question and your answer is just about 1min, so I assume you're trying to share some information to debug for these long running scripts? – fuyushimoya Jun 18 '15 at 18:17
  • @fuyushimoya Yes, that's right. – chessweb Jun 18 '15 at 18:22
  • It's somehow still a little complext to achieve the monitoring things, anyway, I'll upvote you for that lib. – fuyushimoya Jun 18 '15 at 18:26

1 Answers1

1

It turns out there is a way to achieve this. Using a Queue data structure (e.g. http://code.stephenmorley.org/javascript/queues/), an interval timer and some small modification to the control flow of the original process one can build a GUI that doesn't freeze the browser, leaves the process fully debuggable and even allows additional features like stepping, pausing and stopping.

Here is how it goes:

<html>

<head>

    <script src="http://code.stephenmorley.org/javascript/queues/Queue.js"></script>
    <script>
        // The GUI controlling process execution
        var Gui = function(start) {
            this.timer = null; // timer to check for inputs and/or commands for the process
            this.carryOn = false; // used to start/pause/stop process execution
            this.cmdQueue = new Queue(); // data structure that holds the commands 
            this.p = null; // process instance
            this.start = start;
            this.i = start; // input to the modified process 
        }

        Gui.prototype = {
            /**
             * Receives a command and initiates the corresponding action 
             */
            executeCmd: function(cmd) {
                switch (cmd.action) {
                    case "initialize":
                        this.p = new Process(this);
                        break;
                    case "process":
                        this.p.run(cmd.i);
                        break;
                }
            },

            /*
             * Places next command into the command queue
             */
            nextInput: function() {
                this.cmdQueue.enqueue({
                    action: "process",
                    i: this.i++
                });
            }
        }

        // The modified loop-like process
        var Process = function(gui) {
            this.gui = gui;
        }

        Process.prototype.run = function(i) {
            // The workload from the original process above
            console.log(i);

            // The loop itself is controlled by the GUI
            if (this.gui.carryOn) {
                this.gui.nextInput();
            }
        }

        // Event handlers for GUI interaction
        window.onload = function() {

            var gui = new Gui(100);

            document.getElementById("init").onclick = function() {
                gui.cmdQueue.enqueue({ // first command will instantiate the process
                    action: "initialize"
                });

                // Periodically check the command queue for commands
                gui.timer = setInterval(function() {
                    if (gui.cmdQueue.peek() !== undefined) {
                        gui.executeCmd(gui.cmdQueue.dequeue());
                    }
                }, 4);
            }

            document.getElementById("step").onclick = function() {
                gui.carryOn = false; // execute just one step
                gui.nextInput();
            }

            document.getElementById("run").onclick = function() {
                gui.carryOn = true; // (restart) and execute until further notice
                gui.nextInput();
            }

            document.getElementById("pause").onclick = function() {
                gui.carryOn = false; // pause execution
            }

            document.getElementById("stop").onclick = function() {
                gui.carryOn = false; // stop execution and clean up 
                gui.i = gui.start;
                clearInterval(gui.timer)

                while (gui.cmdQueue.peek()) {
                    gui.cmdQueue.dequeue();
                }
            }
        }
    </script>
</head>

<body>
    <input id="init" type="button" value="Init" />
    <input id="step" type="button" value="Step" />
    <input id="run" type="button" value="Run" />
    <input id="pause" type="button" value="Pause" />
    <input id="stop" type="button" value="Stop" />
</body>

</html>

While this approach certainly doesn't fit all long-running scripts one can think of, it certainly can be adapted to any loop-like scenario. I'm using it to port Numenta's HTM/CLA artificial intelligence algorithms to the browser.

chessweb
  • 4,613
  • 5
  • 27
  • 32