Starting newly-inserted – Basj Jul 25 '22 at 09:07

  • 1
    Instead of populating the `#container` element inside the main document, you could perhaps do this stuff inside in iframe? Then you could throw the iframe content away, and all script execution that happened (or still happens) inside the iframe, should be gone as well. (And if you use a simple assignment to `srcdoc` to populate the iframe, then I think you don't even need to jump thru extra `eval` hoops to get the script elements to execute.) – CBroe Jul 25 '22 at 09:20
  • The real answer is DO NOT USE EVAL. Build a correct system that does not rely on eval. – epascarello Jul 29 '22 at 21:11
  • Which general solution would you use here @epascarello? – Basj Jul 30 '22 at 14:16
  • @CBroe No, I prefer to not use iframe. The goal is to be able to have a lightweight website with AJAX requests for navigation, so I prefer avoid iframes for this. – Basj Jul 30 '22 at 14:47
  • 2 Answers2

    2

    You can wrap around the setTimeout before eval() the script. When removed the script, you can unregister the tasks.

    function mockInternal() {
        const setTimeout = window.setTimeout;
        const setInterval = window.setInterval;
        // window.setImmediate
        // window.addEventListener
    
        const setTimeoutHandlers = [];
        const setIntervalHandlers = [];
    
        window.setTimeout = function mock_setTimeout(callback, delay) {
            const h = setTimeout(callback, delay);
            setTimeoutHandlers.push(h);
            return h;
        }
    
        window.setInterval = function mock_setInterval(callback, delay) {
            const h = setInterval(callback, delay);
            setIntervalHandlers.push(h);
            return h;
        }
    
        return function clearMockInternal() {
            window.setTimeout = setTimeout;
            window.setInterval = setInterval;
            setTimeoutHandlers.forEach(h => clearTimeout(h));
            setIntervalHandlers.forEach(h => clearInterval(h));
        }
    }
    
    const clearMockInternal = mockInternal();
    eval(`setInterval(() => console.log(new Date()), 1000);`);
    
    setTimeout(() => {
        clearMockInternal();
        console.log("should not log Date from now");
    }, 6000);
    Rex Pan
    • 1,458
    • 10
    • 13
    0

    This answer just answer your one question(for interval) but I just wanna share it. You can return values from your eval and use it for later. For example:

    index.html

    <html>
    <head>
    </head>
    <body>
        <button type="button" onclick="run1()">Run first method</button>
        <button type="button" onclick="run2()">Run second method</button>
        <div id="container">
        </div>
        <script>
            var pro1, pro2;
            function run1() {
                if (pro2 != undefined && pro2 != null) {
                    clearInterval(pro2);
                }
                fetch("page1.html").then(r => r.text()).then(html => {
                    var tmp = document.createElement('html');
                    tmp.innerHTML = html;
                    document.querySelector("#container").outerHTML = tmp.querySelector("#container").outerHTML;
                    for (const scr of document.querySelectorAll("#container script")) {
                        pro1 = eval(scr.innerHTML);
                    }
                });
            }
            function run2() {
                if (pro1 != undefined && pro1 != null) {
                    clearInterval(pro1);
                }
                fetch("page2.html").then(r => r.text()).then(html => {
                    var tmp = document.createElement('html');
                    tmp.innerHTML = html;
                    document.querySelector("#container").outerHTML = tmp.querySelector("#container").outerHTML;
                    for (const scr of document.querySelectorAll("#container script")) {
                        var data = eval(scr.innerHTML);
                        pro2 = data;
                    }
                });
            }
        </script>
    </body>
    </html>
    

    page1.html

    <html>
        <head>
    
        </head>
        <body>
            <div id="container">
    
                <script>
                    test();
                    function test() {
                        var i = 0;
                        const interval =
                            setInterval(function () {
                                console.log(i);
                                i++;
                            }, 1000);
                        return interval;
                    };
                </script>
            </div>
        </body>
    </html>
    

    page2.html

    <html>
        <head>
    
        </head>
        <body>
            <div id="container">
    
                <script>
                    test();
                    function test() {
                        var i = 9999;
                        const interval =
                            setInterval(function () {
                                console.log(i);
                                i--;
                            }, 1000);
                        return interval;
                    };
                </script>
            </div>
        </body>
    </html>
    

    Everytime you clicked a button it will stop other interval

    Screenshot for sample:

    Sample

    I hope this helps.

    Onur Gelmez
    • 1,044
    • 7
    • 9
    • Thanks! How would you use this in the general case (could be setInterval or anything else, used by the user of the library)? – Basj Jul 30 '22 at 14:16
    • @Basj you can use this with interval and xhrRequest all you need is return what you need (like if you want to stop timer return interval or if you wanna abort ajax or xhrrequest assign your request to a variable and return it.) I think You can write your own library but there will be limit what you can do. You should find something else than eval. I hope I can explain it. – Onur Gelmez Aug 04 '22 at 10:39