Странность загрузки внешнего скрипта Javascript - PullRequest
0 голосов
/ 08 апреля 2009

Я поддерживаю устаревшее приложение javascript, компоненты которого разделены на 4 файла JS.

Это "Default.aspx", "set1.aspx", "set2.aspx" и "set3.aspx". Страницы ASPX записывают сжатый JS из нескольких (совершенно разных) исходных файлов, принадлежащих их соответствующему набору, и устанавливают заголовок типа содержимого равным «text / javascript».

Приложение вызывается путем добавления ссылки на первый набор и создания объекта основного входа.

<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>

В конце первого набора скриптов (default.aspx) следующий точный код:

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

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

Который загружает второй набор скриптов (set1.aspx). И это работает без ошибок во всех основных браузерах (IE6-8 Firefox Safari Opera Chrome).

Однако, поскольку я некоторое время работал над этим сценарием, я хотел бы упростить вызовы функций во многих местах и ​​по ошибке вставил указанную выше функцию Script, что приведет к следующему коду:

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

Который при тестировании на тестовой странице теперь выдает следующую ошибку во всех браузерах:

MyApp is not defined.

Это происходит в строке: ax = new MyApp(..., как отладчик Visual Studio JS и Firebug сообщает об этом.

Я пробовал разные методы в первых 4 ответах на этот вопрос, но безрезультатно. Единственное, что позволит MyApp успешно загружаться, - это только поместив действительный код «add script» в функцию (то есть строку document.write('script')):

Если я помещаю строку document.write внутри функции, она работает, в противном случае это не так. Что происходит?

Разделение и / или экранирование текста сценария не работает.

Ответы [ 4 ]

5 голосов
/ 08 апреля 2009

Чтобы увидеть проблему, посмотрите на верхнюю строку в элементе скрипта:

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

Итак, HTML-парсер обнаруживает открывающий тег . Внутри нормальный синтаксический анализ отключен (в терминах SGML элемент имеет содержимое CDATA). Чтобы определить, где заканчивается блок скрипта, анализатор HTML ищет соответствующий закрывающий тег .

Первый найденный - строковый литерал. Анализатор HTML не может знать, что он находится внутри строкового литерала, потому что анализаторы HTML ничего не знают о синтаксисе JavaScript, они знают только о CDATA. Итак, что вы на самом деле говорите:

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

То есть незамкнутый строковый литерал и незавершенный вызов функции. Это приводит к ошибкам JavaScript, и нужный тег сценария никогда не записывается.

Типичная попытка решить проблему:

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

Это все еще технически неправильно (и не будет проверяться). Это связано с тем, что в SGML последовательность символов, которая заканчивается элементом CDATA, на самом деле не is ’, а просто‘ </ ’- последовательность, которая все еще присутствует в строке выше. Браузеры, как правило, более снисходительны и на практике это позволят. </p>

Вероятно, лучшее решение - избежать последовательности. Есть несколько возможностей, но самый простой - использовать строковые литералы JavaScript ('\ xNN'):

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

Приведенное выше экранирует все символы «<», «>» и «&», что не только останавливает последовательность «</», появляющуюся в строке, но и позволяет вставлять ее в блок сценария XHTML, не вызывая ошибок . </p>

(В XHTML такой вещи, как элемент CDATA, не существует, поэтому эти символы будут иметь то же значение, что и при включении в обычный контент, а строка «» внутри блока сценария фактически создаст вложенный элемент сценария ! Можно разрешить <> & в блоке скрипта XHTML, используя раздел <! [CDATA [, но это немного уродливо и обычно лучше избегать использования этих символов во встроенном скрипте.) </p>

1 голос
/ 08 апреля 2009

Вы также можете попробовать:

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

Steve

1 голос
/ 08 апреля 2009

1) Убедитесь, что вы не пытаетесь ссылаться на MyApp до того, как скрипт «фактически» будет включен в вашу страницу.

2) Попробуйте разбить слово «script» в вашем встроенном загрузчике так:

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

В качестве альтернативы, используйте этот синтаксис, который я позаимствовал из кода Google Analytics и смог успешно использовать:

<script type="text/javascript">
document.write(unescape("%3Cscript src='set1.aspx?v=1234' type='text/javascript'%3E%3C/script%3E"));
</script>
0 голосов
/ 08 апреля 2009

Если бы вы могли использовать JQuery, вы могли бы использовать следующее:

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

Это загружает скрипт в глобальный контекст JavaScript. Убедитесь, что вы указали тип содержимого ответа "text / javascript".

Надеюсь, это поможет ...

...