2009-12-17 4 views
2

Fond

Je travaille sur un projet qui s'exécute dans un navigateur Web intégré dans un petit appareil avec des ressources limitées. Le navigateur lui-même est un peu daté et a des limites à ses capacités (HTML 4.01 †, W3C DOM niveau 2 †, JavaScript 1.4). Je n'ai aucune documentation sur le navigateur, donc ce que je sais vient d'essais et d'erreurs.Autres méthodes pour créer du JavaScript dynamique?

Le but est de récupérer du contenu dynamique à partir d'un serveur de sorte que seul un minimum de code inflexible doit être intégré dans le périphérique exécutant le navigateur Web. Le navigateur ne prend pas en charge l'objet XMLHTTPRequest, donc AJAX est désactivé. En travaillant avec, j'ai écrit un peu de code de test pour insérer dynamiquement JavaScript.

† parties mineures de ces normes ne sont pas supportées

EDIT Bien que je ne peux pas confirmer en fait, je crois que this site peut lister le support DOM du navigateur intégré parce que je vois « Mozilla/4.0 (compatible; EBSWebC 2.6; Windows NT 5.1) "en tant qu'agent utilisateur dans le journal du serveur.

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

Méthode 1

I mis en œuvre d'abord la fonction dynamicJS utilisant Méthode 1 et a constaté que si le code est exécuté comme prévu dans Chrome, IE8 et FireFox 3.5, le JavaScript n'est pas réellement récupéré par le navigateur intégré lorsque l'élément est ajouté.

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

Méthode 2

Vous cherchez un travail autour, je mis en œuvre Méthode 2. Cette méthode fonctionne réellement dans le navigateur intégré lorsque le JavaScript est récupéré et exécuté, mais il ne fonctionne pas dans d'autres navigateurs Web modernes que j'ai testés (Chrome, IE8, FireFox 3.5).

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

Question

Je suis nouveau JavaScript et programmation web en général, donc j'espère un (ou plusieurs) des experts ici peut faire la lumière sur ce point pour moi.

Y at-il quoi que ce soit sur le plan technique mal avec Méthode 2 et sinon, pourquoi ne pas travailler dans les navigateurs web modernes?

+0

Ce n'est probablement pas cela, mais j'ai eu quelques problèmes dans le passé avec un navigateur qui n'analysait pas une balise de script s'il n'y avait pas de contenu à l'intérieur. Je fais une règle de mettre un 'espace' dans une balise de script quand je l'inclue sur une page. Peut-être qu'avec method1, vous pourriez définir js.innerText = ''; ou dans Method2, ajoutez un espace entre les balises de script. –

Répondre

2

bien que tous les navigateurs modernes prennent en charge, La propriété innerHTML n'a pas encore été effectivement normalisé, et le projet de norme de HTML5 inclut a definition of how it should work. Selon le HTML5 specification:

Une fois inséré en utilisant la méthode document.write(), script éléments execute (généralement de manière synchrone), mais lorsqu'il est inséré en utilisant des attributs innerHTML et outerHTML, ils ne menons pas du tout.

innerHTML a d'abord été introduit dans Microsoft Internet Explorer 4, et en raison de sa popularité parmi les auteurs, a été adopté par tous les autres navigateurs, ce qui est ce qui a conduit à son inclusion dans HTML5. Donc, nous allons vérifier Microsoft's documentation:

Lorsque vous utilisez innerHTML pour insérer script, vous devez inclure l'attribut DEFER dans l'élément script.

Donc, apparemment, dans IE vous pouvez obtenir des scripts insérés via innerHTML pour exécuter, mais seulement si vous ajoutez un attribut defer (je n'ai pas IE devant moi pour tester cette). defer est une autre fonctionnalité qui a d'abord été ajoutée à IE; il était included in HTML 4.01, mais n'a pas été récupéré par les autres navigateurs pendant un certain temps. HTML5 inclut une description beaucoup plus détaillée de la façon dont <script defer> devrait fonctionner, bien qu'il semble être légèrement incompatible avec son fonctionnement dans IE, car il ne permet pas l'exécution de scripts ajoutés via innerHTML. La définition HTML5 de <script defer>appears to be implemented in Firefox 3.5 and Safari 4.

En résumé, innerHTML n'a pas encore été standardisé, mais simplement implémenté par tous les fournisseurs de navigateurs de manière légèrement différente. Dans IE, l'implémentation d'origine, il ne supportait pas l'exécution de scripts sauf avec un attribut defer, et defer n'a pas été supporté dans les autres navigateurs jusqu'à récemment, et donc les autres navigateurs ne supportent tout simplement pas l'exécution de scripts ajoutés en utilisant . Ce comportement est ce que HTML5 normalise, donc à moins que les objets Microsoft, va probablement être ce qui va dans la norme.

Il semble que le navigateur avec lequel vous travaillez n'ait pas fait un bon travail d'implémentation d'un innerHTML compatible, car il exécute des scripts ajoutés en utilisant innerHTML n'importe quoi. Ce n'est pas surprenant, car le comportement n'est pas standardisé et doit donc être modifié ou récupéré à la lecture de la documentation des autres navigateurs (ce qui peut ne pas l'avoir été dans le passé).L'un des principaux objectifs de HTML5 est d'écrire toutes ces suppositions non écrites et comportements non documentés, de sorte qu'à l'avenir, quelqu'un qui met en œuvre un navigateur puisse le faire sans être trompé par une spécification qui ne correspond pas à la réalité, ou sans faire l'effort de l'ingénierie inverse des navigateurs existants.

Il me semble que vous pourriez avoir à utiliser Méthode 2 sur votre navigateur intégré, et Méthode 1 si vous voulez exécuter sur les navigateurs de bureau communs. Il serait sans doute une bonne idée d'essayer Méthode 1 d'abord, et revenir à Méthode 2 si cela ne fonctionne pas, puis l'erreur sur (ou échouer en mode silencieux, en fonction de vos besoins) si ni l'un fonctionne.

3

Il n'y a rien de mal techniquement avec la méthode 2 mais la plupart des navigateurs modernes ont des analyseurs HTML très lâches qui ont tendance à se retrouver dans le code que vous envoyez. Spécifiquement, ils analysent le </script> dans votre littéral de chaîne JavaScript en tant que balise de fin. Cela se manifeste de deux manières:

  1. Vous verrez une erreur "Littéral chaîne non terminée".
  2. Tout le code après le </script> sera affiché comme texte sur la page.

Une solution de contournement commune pour ce problème consiste à diviser le </script>. Vous pouvez le faire avec le code suivant. Oui, je sais que c'est un hack, mais cela fonctionne autour du problème.Cependant, de manière réaliste, vous devriez être capable d'utiliser strictement votre première approche en utilisant les API du DOM. J'ai trouvé que certains navigateurs peuvent être très pointilleux sur le chargement des scripts ajoutés par script en ce sens qu'ils ne les chargeront que s'ils sont placés en tant qu'enfant de l'élément <head>. C'est ainsi que fonctionne YUILoader, je serais donc surpris si cela ne fonctionnait pas dans tous les navigateurs.

Voici un exemple, vous voudrez vérifier cela pour vous assurer que cela fonctionne dans tous les navigateurs, et ajouter un peu d'erreur en supposant qu'il y aura un élément <head> mais il vous donnera l'idée générale.

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); 
} 
+0

Je n'arrive pas à obtenir votre solution de contournement pour fonctionner dans IE8, Chrome ou FireFox 3.5. IE8 ne montre pas que l'élément a été ajouté. Chrome montre que l'élément est ajouté, mais le JavaScript n'est pas récupéré (les journaux du serveur le confirment). En utilisant Firebug avec FireFox 3.5, je vois que l'élément est ajouté et le message d'erreur indique qu'il n'a pas réussi à charger la source (les logs du serveur le confirment). Cette méthode d'insertion dynamique de JavaScript semble uniquement fonctionner dans le navigateur intégré. – jschmier

+0

J'ai ajouté une implémentation de getElementsByTagName() si le navigateur ne l'a pas en natif. Je l'ai testé et il fonctionne dans IE, FF et Chrome tant que vous ne l'appelez qu'après que le document soit entièrement chargé - il suffit de l'appeler dans un délai d'expiration ou dans une étiquette de script vers la fin de votre document. –

+0

J'ai mis à jour la méthode 2 pour montrer ce que j'ai essayé. Il ne fonctionne toujours pas dans les navigateurs modernes et je suis toujours curieux de savoir pourquoi. – jschmier

0

Un long métrage mais le navigateur intégré prend-il en charge les iframes? Et si oui, seriez-vous capable de l'utiliser pour charger le JS supplémentaire dont vous avez besoin et y accéder via l'iframe?

Questions connexes