Use JavaScript to prevent a later `[removed]` tag from being evaluated?

前端 未结 7 697
北海茫月
北海茫月 2020-12-13 04:24

This is a bit of an oddball use case, but I have my reasons:

I\'d like to be able to write



        
相关标签:
7条回答
  • 2020-12-13 04:46

    you may use setTimeout() to delay the execution of some code

    0 讨论(0)
  • 2020-12-13 04:47

    In first.js, set var shouldILoad = true

    Then, load second.js this way:

    <script>
        if (shouldILoad) {
            (function() {
                var myscript = document.createElement('script');
                myscript.type = 'text/javascript';
                myscript.src = ('second.js');
                var s = document.getElementById('myscript');
                s.parentNode.insertBefore(myscript, s);
            })();
        }
    </script>
    

    (where 'myscript' is the ID of some element before which you'd like to insert the new Script element)

    0 讨论(0)
  • 2020-12-13 04:49

    All <script> tags have their own execution context, which makes it nearly impossible to interfere with each other. Of course you've got the (infamous) global object (referenced by window in browsers).

    Preventing the execution of second.js is rather simple: break it! Assuming that second.js tries to call document.getElementById for example:

    Working example of breaking jQuery, then loading later (with dependecies).
    Tested on: IE 6+, FF 3.6+, Chrome

    end of first.js

    var execute;
    
    // saving our position
    var scripts = document.getElementsByTagName("script");
    var i = scripts.length;
    
    // breaking getElementById
    var byId = document.getElementById;
    document.getElementById = null;
    
    var interval = setInterval(function () {
        if (i != scripts.length) {
          var second = scripts[i];
          // stop polling
          clearInterval(interval);
          // fix getElementById
          document.getElementById = byId;
          // set the delayed callback
          execute = function (onload) {
            var script = document.createElement("script");
            script.src = second.src;
            script.onload = script.onreadystatechange = onload;
            document.getElementsByTagName("head")[0].appendChild(script);
          };
        }
    }, 100);
    

    anytime you wanna execute second.js

    execute(function(){
       // second.js dependant code goes here...
    });
    

    Note: the onload parameter for execute is optional.

    0 讨论(0)
  • 2020-12-13 04:51

    Given your specific requirements set, this is actually quite simple and should work completely cross-browser. It does require however, that first.js immediately precedes second.js without anything between them except white space.

    First, let's assume that the HTML looks like this:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Test Case</title>
        <meta charset="UTF-8" />
        <script type="text/javascript">
          function func() {
            window.meaningOfLife = 42;
            window.loadSecond();
          };
        </script>
        <script type="text/javascript" src="first.js"></script>
        <script type="text/javascript" src="second.js"></script>
      </head>
      <body>
        <p>Lorem ipsum dolor sit amet ...</p>
        <a href="javascript:func()">Run Func()</a>
      </body>
    </html>
    

    I've removed the setTimeout because that can cause func() to run before start.js runs causing a "loadSecond is not defined" error. Instead, I've provided an anchor to be clicked on to run func().

    Second, let's assume that second.js looks like this:

    document.body.appendChild(document.createTextNode("second.js has run. "));
    if (window.meaningOfLife !== 42) {throw new Error();}
    

    Here, I've just added a line to append some text to the document body, so that it is easier to see when second.js actually runs.

    Then the solution for first.js is this:

    function loadSecond()
    {
        var runSecond = document.createElement("script");
        runSecond.setAttribute("src", "second.js"); 
        document.body.appendChild(runSecond);
    }
    
    document.write("<script type='application/x-suppress'>");
    

    The loadSecond function is just there to run second.js when func() runs.

    The key to the solution is the document.write line. It will inject into the HTML <script type='application/x-suppress'> between the close script tag of first.js and the open script tag of second.js.

    The parser will see this and start a new script element. Because the type attribute has a value which is not one that the browser recognises as being JavaScript, it will not attempt to run its content. (So there are an infinite number of possible type attribute values you could use here, but you must include a type attribute, as in its absence, the browser will assume that the script's content is JavaScript.)

    The second.js script's opening tag will then be parsed as text content of the new script element and not executed. Finally the second.js script's closing tag will be re-purposed to close the new script element instead, which means that the remainder of the HTML is parsed correctly.

    You can see a working version at http://www.alohci.net/static/jsprevent/jsprevent.htm

    0 讨论(0)
  • 2020-12-13 04:55

    Following article describes the way you could block (3-rd party) scripts loading/execution from your script (including the both tag in the page head and dynamically added tags).

    To handle existing tags on a page:

    1. Use a MutationObserver to observe script elements insertion and inside the MutationObserver callback backup the script (to enable/insert it later) and change the script type to "javascript/blocked" (not works in IE, Edge, Firefox). Also you could handle deprecated (but working) beforescriptexecute event in Firefox to prevent script load.
    2. Manually set type "javascript/blocked" (works everywhere including IE and Edge) like <script type="text/javascript" type="javascript/blocked" src="second.js"></script>, then backup it in MutationObserver callback and re-add it later.

    To handle dynamically added tags

    1. Monkey-patch the document.createElement.
    2. Override ‘src’ and ‘type’ descriptors on the HTMLScriptElement prototype.

    Also this guys provide a yett library with the approach described in the article.

    0 讨论(0)
  • 2020-12-13 04:59

    Just to see if this was possible, I had first.js send a synchronous XHR to a PHP file, and had the PHP file delete second.js. When the readyState reached '4', I had the JS alert something, to stop the thread. Then I went and checked the server... Yeah, second.js was deleted. And yet, it wouldn't work. I'd close the alert box, and the code that was in second.js would still be executed, despite the fact that the file was gone.

    I don't really know what this means, but the answer to your question is probably, "No, it's not possible."

    0 讨论(0)
提交回复
热议问题