动态添加的javascript与外部脚本不会被执行 [英] Dynamically added javascript with external script doesn't get executed

查看:70
本文介绍了动态添加的javascript与外部脚本不会被执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以这就是我们的场景......我们首先要做的是,我们附加一段javascript代码,将外部脚本添加到文档中:

 (function(){
var e = document.createElement('script'); e.type ='text / javascript'; e.async = true; e.src ='http ://blabla.com/script.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e,s);
})() ;

然后在 script.js 发生以下情况:

  function ajaxCall(){
// ...一些脚本发送ajax请求后调用createDiv()成功
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject(Microsoft.XMLHTTP);
}
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4&& xmlhttp.status == 200){
createDiv(xmlhttp.responseText) ;
}
};
xmlhttp.open(GET,http://blabla.com/api/);
xmlhttp.send();
}
函数parseResponse(响应){
var parser = new DOMParser();
var dom = parser.parseFromString(response,text / html);
返回dom;
}
函数createDiv(responsetext)
{
var dom = parseResponse(responsetext);

var _ws = dom.getElementById('styles');
var h = document.getElementsByTagName('head')[0];
h.appendChild(document.importNode(_ws,true));

var _jr = dom.getElementById('script1')。outerHTML;
var _vc = dom.getElementById('script2')。outerHTML;
var _rv = dom.getElementById('script3')。outerHTML;

var _rw = dom.getElementById('my_div');
var _b = document.getElementsByTagName('body')[0];
var _d = document.createElement('div'); _d.id ='just_id';
_d.innerHTML = _jr + _vc + _rv;
_d.appendChild(document.importNode(_rw,true));
_b.appendChild(_d);
}
ajaxCall();

一切正常,脚本和div正如预期的那样附加到预期的位置,但是附加脚本不会被执行,也不会影响附加的div 。这是为什么?我怎样才能让它执行?我们也没有在控制台中收到任何警告/错误。使用最新的Firefox。



编辑1



评论:示例您展示的脚本只是定义函数,但它实际上从不调用它们



它实际上调用了一个发出ajax请求的函数,请检查编辑过的代码片段。



编辑2



评论:您是否尝试过逻辑在回调中,然后在createDiv中调用它?可能会添加一些日志来测试它是否被调用但它无法找到div



我刚试过 console.log(' hello world'); 调用其中一个脚本,这些脚本被 createDiv()函数追加,但它什么也没做。



编辑3



了解更多详情。当页面加载时,我可以看到

 < script type =text / javascriptid =script1src = http://blabla.com/script1.js\"></script> 
< script type =text / javascriptid =script2src =http://blabla.com/script2.js>< / script>
< script type =text / javascriptid =script3src =http://blabla.com/script3.js>< / script>
< div id =just_id>此处的内容< / div>

在DOM-Inspector中,如上所述,有 console.log( 'hello world'); 来测试它,但它没有被执行。



编辑4



通过 createDiv()添加一些CSS来记录文件的< head>< / head> 并且它会影响id为'just_id'的div。 JS仍然无法正常工作。



编辑5



还尝试追加在我的函数中内联javascript而不是外部javascript,但仍然没有成功。可以在DOM-Inspector中看到以下内容,但代码不会记录任何内容。

 < script type =text / javascript > 
console.log('test');
< / script>

编辑6



我还尝试从



第二张图片是script.js的源代码,它正在192.168.2.197/testing/whatever/etc上加载。 .htaccess与上面的示例相同:





第3张图片是检查员的屏幕截图,我的dom看起来如何:





第4张图片......没有任何反应。只是一个与我的问题无关的警告(我希望如此),因为即使我删除所有脚本,它仍然会出现。





这是一个firefox错误吗?

解决方案

问题是上面的代码是将 appendChild innerHTML 混合。在某些情况下,两者的表现不同,这在直觉上并不明显。前者允许新插入的脚本节点在附加到DOM时执行。后者没有。对许多人来说,这一直是一个令人头疼的问题。好吧谷歌脚本和innerHTML,你会发现你并不是唯一面临这个类似问题。



如果你(1)改变

  _d.innerHTML = _jr + _vc + _rv 

to

  _d.appendChild(document.importNode(_jr)); 
_d.appendChild(document.importNode(_vc));
_d.appendChild(document.importNode(_rv));

另外(2)更改

  var _jr = dom.getElementById('script1')。outerHTML; 
var _vc = dom.getElementById('script2')。outerHTML;
var _rv = dom.getElementById('script3')。outerHTML;

  var _jr = dom.getElementById('script1'); 
var _vc = dom.getElementById('script2');
var _rv = dom.getElementById('script3');

然后您的脚本将被执行。以下是演示:



  var b = document.getElementsByTagName('body' )[0]; / * Works * / var s1 = document.createElement('script'); s1.innerHTML =console.log('我将执行'); b.appendChild(s1); / *失败* / var s2 = document.createElement('script'); s2.innerHTML =while(1){alert('别担心!我不会执行');}; b.innerHTML = s2.outerHTML; console。 log(它没有执行);  



经过测试



我在我的服务器上运行了OP的代码以尽可能地复制问题。鉴于提供的代码,我可以使它在我的服务器上按预期工作。我只将AJAX URL从 http://blabla.com/api/ 更改为 api.html 并提供了我的自己的文件,因为没有提供OP,但我拼凑了它应该包含在OP的JavaScript中)。以下是示例结果:



index.html

 < html lang =en> 
< body>
< script>
(function(){
var e = document.createElement('script'); e.type ='text / javascript'; e.async = true; e.src ='script.js' ;
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e,s);
})();
< / script>
< / body>
< / html>

script.js



这是OP的代码修改为我上面的规范(使用 appendChild 而不是 innerHTML 和AJAX call返回下面api.html的内容)

  function ajaxCall(){
// ...一些脚本发送成功后调用createDiv()的ajax请求
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject(Microsoft.XMLHTTP);
}
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4&& xmlhttp.status == 200){
createDiv(xmlhttp.responseText) ;
}
};
xmlhttp.open(GET,api.html);
xmlhttp.send();
}
函数parseResponse(响应){
var parser = new DOMParser();
var dom = parser.parseFromString(response,text / html);
返回dom;
}
函数createDiv(responsetext)
{
var dom = parseResponse(responsetext);

var _ws = dom.getElementById('styles');
var h = document.getElementsByTagName('head')[0];
h.appendChild(document.importNode(_ws,true));

var _jr = dom.getElementById('script1');
var _vc = dom.getElementById('script2');
var _rv = dom.getElementById('script3');

var _rw = dom.getElementById('my_div');
var _b = document.getElementsByTagName('body')[0];
var _d = document.createElement('div'); _d.id ='just_id';

_d.appendChild(document.importNode(_jr,true));
_d.appendChild(document.importNode(_vc,true));
_d.appendChild(document.importNode(_rv,true));

_d.appendChild(document.importNode(_rw,true));
_b.appendChild(_d);
}
ajaxCall();

api.html (由AJAX电话回复)

 <!DOCTYPE html> 
< html>
< body>
< style type =text / cssid =styles>< / style>
< script type =text / javascriptid =script1src =script1.js>< / script>
< script type =text / javascriptid =script2> console.log(倾斜脚本2)< / script>
< script type =text / javascriptid =script3> console.log(倾斜脚本3)< / script>
< div id =my_div>< / div>
< / body>
< / html>

script1.js

  console.log(src script1); 

以下是DevTools结果,显示这是有效的。






So this is our scenario... First thing we do is, we append a piece of javascript code which adds external script to document like this:

(function() {
     var e = document.createElement('script'); e.type = 'text/javascript'; e.async = true; e.src = 'http://blabla.com/script.js';
     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s);
})();

Then in script.js following happens:

function ajaxCall() { 
    //... some script to send ajax request which calls createDiv() after success
   if (window.XMLHttpRequest){
      xmlhttp=new XMLHttpRequest();
   }
   else{
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
   }
   xmlhttp.onreadystatechange=function(){
      if(xmlhttp.readyState==4&&xmlhttp.status==200){
         createDiv(xmlhttp.responseText);
      }
   };
   xmlhttp.open("GET","http://blabla.com/api/");
   xmlhttp.send(); 
}
function parseResponse(response) {
    var parser = new DOMParser();
    var dom = parser.parseFromString(response, "text/html");
    return dom;
}
function createDiv(responsetext)
{
   var dom = parseResponse(responsetext);

   var _ws = dom.getElementById('styles');
   var h = document.getElementsByTagName('head')[0];
   h.appendChild(document.importNode(_ws, true));

   var _jr = dom.getElementById('script1').outerHTML;
   var _vc = dom.getElementById('script2').outerHTML;
   var _rv = dom.getElementById('script3').outerHTML;

   var _rw = dom.getElementById('my_div');
   var _b = document.getElementsByTagName('body')[0];
   var _d = document.createElement('div'); _d.id = 'just_id';
   _d.innerHTML = _jr + _vc + _rv;
   _d.appendChild(document.importNode(_rw, true));
   _b.appendChild(_d);
}
ajaxCall();

Everything works fine, script's and a div are being appended as expected and where expected, but appended script doesn't get executed and doesn't affect appended div. Why is that? And how can I make it execute? We also don't get any warnings/errors in console. Using latest firefox.

EDIT 1

Comment: The example script you showed just defines function, but it never actually calls them

It actually calls a function which makes an ajax request, please check edited code snippet.

EDIT 2

Comment: Have you tried to put the logic in a callback and then call it in createDiv? May be add some logs to test if its getting called but it unable to find div

I just tried console.log('hello world'); call in one of scripts which are being appended by createDiv() function, but it does nothing.

EDIT 3

For more details. When page is loaded, I can see

<script type="text/javascript" id="script1" src="http://blabla.com/script1.js"></script>
<script type="text/javascript" id="script2" src="http://blabla.com/script2.js"></script>
<script type="text/javascript" id="script3" src="http://blabla.com/script3.js"></script>
<div id="just_id">Content here</div>

In DOM-Inspector and as mentioned above, there is console.log('hello world'); to test it, but it doesnt get executed.

EDIT 4

Added some CSS through createDiv() function to document's <head></head> and it affects my div with id 'just_id'. JS still isn't working.

EDIT 5

Also tried to append inline javascript instead of external one in my function, but still no success. Can see following in DOM-Inspector, but code doesn't log anything.

<script type="text/javascript">
   console.log('test');
</script>

EDIT 6

I also tried to import nodes from as suggested here

This method is not allowed to move nodes between different documents. If you want to append node from a different document the document.importNode() method must be used.

and also tried to changed order. 1.css 2.div 3.js like this but still no success... Anyone has an idea what is going on here?

Check the code above

EDIT 7

As suggested in How do you execute a dynamically loaded JavaScript block? I set innerHTML of my div to scripts + content and then appended to DOM like this:

Check the code above

But still without any success.

EDIT 8

Added ajax function code. 3rd paramter in xmlhttp.open("GET","http://blabla.com/api/"); true (asynchronous) and false (synchronous) already tried. Still no success.

EDIT 9

function createDiv() as suggested in answer:

var dom = parseResponse(responsetext);

var _jr = dom.getElementById('script1'); //<script> tag with src attribute
var _vc = dom.getElementById('script2'); //inline <script> for test purposes only, it should actualy be external script also
var _rv = dom.getElementById('script3'); //inline <script>

var _rw = dom.getElementById('external_div');
var _b = document.getElementsByTagName('body')[0];
var _d = document.createElement('div'); _d.id = 'internal_div';
_d.appendChild(document.importNode(_rw, true));
_d.appendChild(document.importNode(_jr, true));
_d.appendChild(document.importNode(_rv, true)); //without second parameter TRUE, I dont get script content
_d.appendChild(document.importNode(_vc, true)); //without second parameter TRUE, I dont get script content
_b.appendChild(_d);

Doesn't work. Work's only if I take innerHTML of inline scripts from other document, create elements like suggested in answer, set their innerHTML and then append do current document. External script's wont load at all.

EDIT 10

.htaccess from localhost... :

<Files *.html>
    Order Deny,Allow
    Deny from all
    Allow from 127.0.0.1
</Files>

<Files *.php>
    Order Deny,Allow
    Deny from all
    Allow from 127.0.0.1
</Files>

<Files index.php>
    Order Allow,Deny
    Allow from all
</Files>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /page1/
#RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
</IfModule>

.htaccess from 192.*** ... :

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /direktexpress/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /page2/index.php [L]
</IfModule>
# END WordPress

EDIT 11

So I am probably going to give bounty @Drakes, just for the effort and his spent time on my question and going to show some screenshots what is going on. It is definitely firefox bug, I just tested on chrome and it works.

1st picture: source code of 192.168.2.197/testing/whatever/etc. .htaccess remains the same as in example above

2nd picture is source code for script.js, which is being loaded on 192.168.2.197/testing/whatever/etc. .htaccess remains the same as in example above:

3rd picture is a screenshot of inspector, how does my dom look like:

4th picture.... nothing happens. Just a warning which has nothing to do with my problem (I hope so), because even when I remove all scripts, it still appears.

Is it a firefox bug?

解决方案

The problem is that the code above is mixing appendChild with innerHTML. It's not intuitively obvious that the two perform differently in some cases. The former allows newly inserted script nodes to be executed as they are attached to the DOM. The latter doesn't. This has been a head-scratcher for many people. Kindly Google "script and innerHTML" and you will find that you are not alone facing this similar problem.

If you (1) change

_d.innerHTML = _jr + _vc + _rv

to

_d.appendChild(document.importNode(_jr));
_d.appendChild(document.importNode(_vc));
_d.appendChild(document.importNode(_rv));

and additionally (2) change

var _jr = dom.getElementById('script1').outerHTML;
var _vc = dom.getElementById('script2').outerHTML;
var _rv = dom.getElementById('script3').outerHTML;

to

var _jr = dom.getElementById('script1');
var _vc = dom.getElementById('script2');
var _rv = dom.getElementById('script3');

then your scripts will get executed. Here is a demonstration:

var b = document.getElementsByTagName('body')[0];

/* Works */
var s1 = document.createElement('script');
s1.innerHTML = "console.log('I will execute')";
b.appendChild(s1);

/* Fails */
var s2 = document.createElement('script');
s2.innerHTML = "while(1){alert('Do not worry! I will not execute');}";
b.innerHTML = s2.outerHTML;
console.log("It didn't execute");

Tested

I ran the OP's code on my server to replicate the problem as best I can. Given the supplied code I can make it work as intended on my server. I only changed the AJAX URL from http://blabla.com/api/ to api.html and supplied my own file as none was provided by the OP, but I pieced together what it should contain from the OP's JavaScript). Here are sample results:

index.html

<html lang="en">
<body>
    <script>
        (function() {
            var e = document.createElement('script'); e.type = 'text/javascript'; e.async = true; e.src = 'script.js';
            var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s);
        })();
    </script>
</body>
</html>

script.js

This is the OP's code modified to my specifications above (using appendChild instead of innerHTML, and the AJAX call returns the contents of api.html below)

function ajaxCall() {
    //... some script to send ajax request which calls createDiv() after success
    if (window.XMLHttpRequest){
        xmlhttp=new XMLHttpRequest();
    }
    else{
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange=function(){
        if(xmlhttp.readyState==4&&xmlhttp.status==200){
            createDiv(xmlhttp.responseText);
        }
    };
    xmlhttp.open("GET","api.html");
    xmlhttp.send();
}
function parseResponse(response) {
    var parser = new DOMParser();
    var dom = parser.parseFromString(response, "text/html");
    return dom;
}
function createDiv(responsetext)
{
    var dom = parseResponse(responsetext);

    var _ws = dom.getElementById('styles');
    var h = document.getElementsByTagName('head')[0];
    h.appendChild(document.importNode(_ws, true));

    var _jr = dom.getElementById('script1');
    var _vc = dom.getElementById('script2');
    var _rv = dom.getElementById('script3');

    var _rw = dom.getElementById('my_div');
    var _b = document.getElementsByTagName('body')[0];
    var _d = document.createElement('div'); _d.id = 'just_id';

    _d.appendChild(document.importNode(_jr, true));
    _d.appendChild(document.importNode(_vc, true));
    _d.appendChild(document.importNode(_rv, true));

    _d.appendChild(document.importNode(_rw, true));
    _b.appendChild(_d);
}
ajaxCall();

api.html (returned by the AJAX call)

<!DOCTYPE html>
<html>
<body>
    <style type="text/css" id="styles"></style>
    <script type="text/javascript" id="script1" src="script1.js"></script>
    <script type="text/javascript" id="script2">console.log("incline script 2")</script>
    <script type="text/javascript" id="script3">console.log("incline script 3")</script>
    <div id="my_div"></div>
</body>
</html>

script1.js

console.log("src script1");

Here are the DevTools results to show this is working.

这篇关于动态添加的javascript与外部脚本不会被执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆