Javascript external script loading strangeness

让人想犯罪 __ 提交于 2019-12-01 13:20:02

问题


I'm maintaining a legacy javascript application which has its components split into 4 JS files.

They are "Default.aspx", "set1.aspx", "set2.aspx" and "set3.aspx". The ASPX pages writes out compressed JS from multiple (all-different) source files belonged to their respective set and set content-type header to "text/javascript".

The application is invoked by adding a reference to the first set and creating the main entry object.

<script src="/app/default.aspx" type="text/javascript"></script>

<script type="text/javascript>

    var ax;  

    // <body onload="OnLoad()">
    function OnLoad() {
        ax = new MyApp(document.getElementById("axTargetDiv"));
    }

</script>

At the end of the first set of scripts (default.aspx) is the following exact code:

function Script(src) {
    document.write('<script src="' + src + '" type="text/javascript"></script>');
}

Script("set1.aspx?v=" + Settings.Version);

Which loads the second set of scripts (set1.aspx). And this works without any errors in all major browsers (IE6-8 Firefox Safari Opera Chrome).

However, as I've been working on this script for quiet sometime, I'd like to simplify function calls in a lot of places and mistakenly inlined the above Script function, resulting in the following code:

document.write('<script src="set1.aspx?v=' + Settings.Version + '" type="text/javascript"></script>');

Which, when tested with a test page, now throws the following error in all browsers:

MyApp is not defined.

This happens at the line: ax = new MyApp(... as Visual Studio JS debugger and Firebug reports it.

I've tried various methods in the first 4 answers posted to this question to no avail. The only thing that will enable MyApp to loads successfully is only by putting the actual "add script" code inside a function (i.e. the document.write('script') line):

If I put the document.write line inside a function, it works, otherwise, it doesn't. What's happening?

Splitting and/or escaping the script text does not work.


回答1:


To see the problem, look at that top line in its script element:

<script type="text/javascript">
    document.write('<script src="set1.aspx?v=1234" type="text/javascript"></script>');
</script>

So an HTML parser comes along and sees the opening <script> tag. Inside <script>, normal <tag> parsing is disabled (in SGML terms, the element has CDATA content). To find where the script block ends, the HTML parser looks for the matching close-tag </script>.

The first one it finds is the one inside the string literal. An HTML parser can't know that it's inside a string literal, because HTML parsers don't know anything about JavaScript syntax, they only know about CDATA. So what you are actually saying is:

<script type="text/javascript">
    document.write('<script src="set1.aspx?v=1234" type="text/javascript">
</script>

That is, an unclosed string literal and an unfinished function call. These result in JavaScript errors and the desired script tag is never written.

A common attempt to solve the problem is:

document.write('...</scr' + 'ipt>');

This is still technically wrong (and won't validate). This is because in SGML, the character sequence that ends a CDATA element is not actually ‘</tagname>’ but just ‘</’ — a sequence that is still present in the line above. Browsers generally are more forgiving and in practice will allow it.

Probably the best solution is to escape the sequence. There are a few possibilities, but the simplest is to use JavaScript string literal escapes ('\xNN'):

document.write('\x3Cscript src="set1.aspx?v=1234\x26w=5678" type="text/javascript"\x3E\x3C/script\x3E');

The above escapes all ‘<’, ‘>’ and ‘&’ characters, which not only stops the ‘</’ sequence appearing in the string, but also allows it to be inserted into an XHTML script block without causing errors.

(In XHTML, there's no such thing as a CDATA element, so these characters would have the same meaning as if included in normal content, and a string '<script>' inside a script block would actually create a nested script element! It's possible to allow <>& in an XHTML script block by using a <![CDATA[ section, but it's a bit ugly and usually better to avoid using those characters in inline script.)




回答2:


1) Assure that you do not try to reference MyApp before the script is "actually" included in your page.

2) Try breaking the word "script" in your inline loader like this:

<script type="text/javascript">
document.write('<scr' + 'ipt src="set1.aspx?v=1234" type="text/javascript"></scr' + 'ipt>');
</script>

Alternatively, use this syntax which i borrowed from google analytics code and have been able to use successfully:

<script type="text/javascript">
document.write(unescape("%3Cscript src='set1.aspx?v=1234' type='text/javascript'%3E%3C/script%3E"));
</script>



回答3:


You could also try:

var script = document.createElement("script");
script.src = "set1.aspx?v=1234";
script.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(script);

Steve




回答4:


If you could use JQuery you could use the following:

$.getScript("set1.aspx?v=1234");

This loads the script into the global javascript context. Make sure you set contenttype of the response to "text/javascript".

Hope this helps...



来源:https://stackoverflow.com/questions/728697/javascript-external-script-loading-strangeness

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!