Альтернативные методы для создания динамического JavaScript? - PullRequest
2 голосов
/ 17 декабря 2009

Фон

Я работаю над проектом, который выполняется во встроенном веб-браузере на небольшом устройстве с ограниченными ресурсами. Сам браузер немного устарел и имеет ограничения по своим возможностям (HTML 4.01 †, W3C DOM Level 2 †, JavaScript 1.4). У меня нет документации по браузеру, поэтому то, что я знаю, происходит методом проб и ошибок.

Смысл заключается в том, чтобы извлекать динамическое содержимое с сервера, чтобы в устройство с веб-браузером необходимо было внедрить только минимальный объем негибкого кода. Браузер не поддерживает объект XMLHTTPRequest, поэтому AJAX отсутствует. Работая со мной, я написал немного тестового кода для динамической вставки JavaScript.

† Незначительные части этих стандартов не поддерживаются

EDIT Хотя я не могу подтвердить это, я считаю, что этот сайт может перечислить поддержку DOM для встроенного браузера, потому что я вижу "Mozilla / 4.0 (совместимый; EBSWebC 2.6; Windows NT 5.1)" как пользовательский агент журнал сервера.

<html> 
<head>  
</head> 
<body onload="init()"> 
<div id="root"></div>
<script type="text/javascript"> 
<!--
function init() {
 // Add a div element to the page.
 var div = document.createElement("div");
 div.id = "testDiv";
 document.getElementById("root").appendChild(div);

 // Set a timeout to insert the JavaScript after 2 seconds.
 setTimeout("dynamicJS()", 2000);
}

function dynamicJS() {
 ...
}
//-->
</script> 
</body> 
</html>

Метод 1

Первоначально я реализовал функцию dynamicJS с использованием Метод 1 и обнаружил, что хотя код выполняется в Chrome, IE8 и FireFox 3.5, как и ожидалось, встроенный браузер фактически не получает JavaScript, когда элемент добавляется.

function dynamicJS() {
 var js = document.createElement("script");
 js.type = "text/javascript";
 js.src = "js/test.js";
 document.getElementById("root").appendChild(js);
}

Метод 2

В поисках обходного пути я реализовал Метод 2 . Этот метод фактически работает во встроенном браузере, так как JavaScript извлекается и выполняется, но он не работает в других современных веб-браузерах, с которыми я тестировал (Chrome, IE8, FireFox 3.5).

function dynamicJS() {
 var js= '<script type="text/javascript" src="js/test.js"> </s' + 'cript>';
 document.getElementById("testDiv").innerHTML = js;
}

Вопрос

Я новичок в JavaScript и веб-программировании в целом, поэтому я надеюсь, что один (или более) из экспертов здесь может пролить свет на это для меня.

Что-то технически не так с Метод 2 и если нет, то почему он не работает в современных веб-браузерах?

Ответы [ 3 ]

3 голосов
/ 17 декабря 2009

Технически нет ничего плохого в методе 2, но большинство современных браузеров имеют очень слабые парсеры HTML, которые, как правило, оказываются в коде, который вы отправляете. В частности, они анализируют </script> в вашем строковом литерале JavaScript как конечный тег. Это проявляется двумя способами:

  1. Вы увидите ошибку «Unterminated String Literal».
  2. Весь код после текста </script> будет отображаться как текст на странице.

Обычный способ решения этой проблемы - разделить </script>. Вы можете сделать это с помощью следующего кода. Да, я знаю, что это взлом, но это решает проблему.

function dynamicJS() {
   var js= '<script type="text/javascript" src="js/test.js"></s' + 'cript>';
   document.getElementById("testDiv").innerHTML = js;
}

Реально, вы должны быть в состоянии использовать свой первый подход строго с использованием API DOM. Я обнаружил, что некоторые браузеры могут быть очень требовательны к загрузке сценариев, добавленных сценарием, поскольку они будут загружать их только в том случае, если они размещены как дочерние элементы элемента <head>. Вот как работает YUILoader, поэтому я был бы удивлен, если бы он не работал во всех браузерах.

Вот пример, вам нужно проверить это, чтобы убедиться, что он работает во всех браузерах, и добавить некоторую проверку ошибок в предположении, что будет элемент <head>, но он даст вам общее представление.

if (!document.getElementsByTagName) {
  document.getElementsByTagName = function(name) {
    var nodes = [];
    var queue = [document.documentElement];
    while (queue.length > 0) {
      var node = queue.shift();
      if (node.tagName && node.tagName.toLowerCase() === name) {
        nodes.push(node);
      }
      if (node.childNodes && node.childNodes.length > 0) {
        for (var i=0; i<node.childNodes.length; i++) {
          if (node.childNodes[i].nodeType === 1 /* element */) {
            queue.push(node.childNodes[i]);
          }
        }
      }
    }
    return nodes;
  };
}

function dynamicJS() {
   var js = document.createElement("script");
   js.setAttribute('type', 'text/javascript');
   js.setAttribute('src', 'js/test.js');
   var head = document.getElementsByTagName('head')[0];
   head.appendChild(js);
}
2 голосов
/ 10 января 2010

Свойство innerHTML на самом деле еще не стандартизировано, хотя все современные браузеры поддерживают его, и черновой стандарт HTML5 включает определение того, как оно должно работать . Согласно спецификации HTML5 :

При вставке с использованием метода <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#dom-document-write" rel="nofollow noreferrer">document.write()</a> элементы <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#script" rel="nofollow noreferrer">script</a> выполняются (обычно синхронно), но при вставке с использованием атрибутов <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#dom-innerhtml" rel="nofollow noreferrer">innerHTML</a> и <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#dom-outerhtml" rel="nofollow noreferrer">outerHTML</a> они не выполняются вообще.

innerHTML впервые был представлен в Microsoft Internet Explorer 4 и благодаря своей популярности среди авторов был принят всеми другими браузерами, что и привело к его включению в HTML5. Итак, давайте проверим документацию Microsoft :

При использовании innerHTML для вставки сценария необходимо включить атрибут DEFER в элемент script .

Таким образом, очевидно, что в IE вы можете запускать сценарии через innerHTML, но только если вы добавляете атрибут defer (у меня нет IE передо мной, чтобы проверить это). defer - еще одна функция, впервые добавленная в IE; он был включен в HTML 4.01 , но долгое время не использовался ни одним из других браузеров. HTML5 включает в себя гораздо более подробное описание того, как <script defer> должен работать, хотя кажется, что оно немного несовместимо с тем, как оно работает в IE, так как не позволяет выполнять сценарии, добавленные через innerHTML. Определение HTML5 <script defer> , по-видимому, реализовано в Firefox 3.5 и Safari 4 .

Таким образом, innerHTML на самом деле еще не стандартизирован, а вместо этого просто реализован всеми поставщиками браузеров немного другими способами. В IE, первоначальной реализации, он не поддерживал выполнение сценариев, кроме как с атрибутом defer, а defer не поддерживался в других браузерах до недавнего времени, и поэтому другие браузеры просто не поддерживают выполнение сценариев, добавленных с использованием innerHTML. Это поведение является тем, что стандартизирует HTML5, поэтому, если объекты Microsoft, вероятно, не будут тем, что входит в стандарт.

Похоже, что браузер, с которым вы работаете, не так хорошо реализовал совместимый innerHTML, поскольку он выполняет скрипты, добавленные с использованием innerHTML, несмотря ни на что. Это неудивительно, поскольку поведение не стандартизировано, поэтому его необходимо либо пересмотреть, либо почерпнуть из прочтения документации других браузеров (которые, возможно, не учитывали этот факт в прошлом). Одна из основных целей HTML5 - записать все эти неписаные предположения и недокументированное поведение, чтобы в будущем кто-то, реализующий браузер, мог это сделать, не будучи введенным в заблуждение спецификацией, не соответствующей действительности, или не имея сделать попытку реверс-инжиниринга существующих браузеров.

Мне кажется, что вам, возможно, придется использовать Метод 2 во встроенном браузере и Метод 1 , если вы хотите работать в обычных браузерах для настольных компьютеров. Вероятно, было бы неплохо сначала попробовать Метод 1 и вернуться к Метод 2 , если это не сработает, а затем выполнить ошибку (или молча завершиться ошибкой, в зависимости от ваших потребностей). ) если ни один из них не работает.

0 голосов
/ 10 января 2010

Долгий путь, но поддерживает ли встроенный браузер фреймы? И если да, то сможете ли вы использовать это для загрузки любого дополнительного JS, который вам нужен, и доступа к нему через iframe?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...