如何异步加载第三方javascript标签,其中有document.write

How to load third-party javascript tag asynchronously which has document.write

本文关键字:标签 write document javascript 第三方 何异步 异步 加载      更新时间:2023-09-26

我们给出了一块javascript标签,如<script src="http://ours.com/some.js"></script>,网站所有者把他们的网站,如http://example.com和在这个javascript标签,我们想动态地包括第三方js,如可以有文档。写在里面,当然,如果我们试图用常规方法包含它,

var script_tag = document.createElement('script');
script_tag.type = 'text/javascript';
script_tag.src="http://third-party.com/some.js";
document.getElementById('target').appendChild(script_tag);

我们从浏览器得到一个警告,

警告:从异步加载的外部脚本被忽略。

我们如何解决这个问题?请记住,我们并不能真正控制第三方脚本,所以我们不能改变其中的逻辑。我们正在寻找一些可以跨所有浏览器工作的解决方案。

在已经加载的文档上加载脚本(而不是让浏览器忽略document.write())的问题是,您将删除所有存在的HTML。查看这个示例,以便您能够准确地理解发生了什么,或者查看document.write()方法的文档页面了解更多细节。

虽然我知道这可能不是你期望得到的答案,但我相信你运气不好,因为重写脚本不是一个选择。

这似乎是一个类似的问题,有类似的回答。

您可以通过拦截对文档的调用来支持脚本注入。这样写:

document.writeText = document.write;
document.write = function(parameter) {
    if (!parameter) return; 
    var scriptPattern = /<script.*?src=['|"](.*?)['|"]/;
    if (scriptPattern.test(parameter)) {
        var srcAttribute = scriptPattern.exec(parameter)[1];
        var script = document.createElement('script');
        script.src = srcAttribute;
        document.head.appendChild(script); 
    }
    else {
        document.writeText(parameter);
    }   
};

显然,这可以进一步压缩,但为了清晰起见,包括变量名。

如果不是通过附加脚本元素来加载脚本,而是使用AJAX调用加载脚本URL的内容,然后使用eval()在全局作用域中运行它,情况如何?下面是一个例子,我对它进行了测试,以验证它是否有效:

<!DOCTYPE html>
<html>
<head>
<script>
var xmlhttp;
if (window.XMLHttpRequest) {
  xmlhttp = new XMLHttpRequest();
}else{
  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
    window.eval(xmlhttp.responseText); //Indirect call to eval to execute in global scope (http://perfectionkills.com/global-eval-what-are-the-options/)
  }
}
xmlhttp.open("GET", "https://third-party.com/test.js", false); //This is synchronous so that any document.write calls don't overwrite the entire page when they get called after the document is finished rendering. For all intents and purposes, this just loads the script like any other script, synchronously.
xmlhttp.send();
</script>
</head>
<body>
<div><h2>Hello World</h2></div>
</body>
</html>
下面是我在test.js文件中的内容:
document.write("This is a test...");
alert("...This is a test alert...");
console.log("...And a console message.");

我使脚本的AJAX请求是同步的,这样它就会像一个普通的嵌入式脚本标记一样被加载。如果您异步运行它,并且脚本使用文档。在页面完全渲染后写入,它清除DOM,然后写入它…实际上有点烦人。让我知道这对你是否有效。:)

文档。写入将无法从异步脚本中工作,因为当脚本开始工作时文档已经加载。

但是你可以这样做:

document.body.innerHTML = document.body.innerHTML + '<h1>Some HTML</h1>';

另一个过程是改变document.write()函数的行为。
假设您有index.php主文件:

<html>
<head>
<meta charset="utf-8" />
</head>
<body>
Hello<br>
<div id="target"></div>
<script>
document.write = function(input) {
    document.body.innerHTML += input;
}
var doit = function() {
    var script_tag = document.createElement('script');
    script_tag.type = 'text/javascript';
    script_tag.src="http://127.0.0.1:8080/testPlace/jsfile.js";
    document.getElementById('target').appendChild(script_tag);
}
</script>
</body>
</html>

jsfile.js是这样的:

document.write("OK MAN!");

现在,如果你在js浏览器控制台中输入doit()来执行该函数(脚本做你写的),那么结果将是:

Hello
OK MAN!

里面的html是这样的:

<html><head>
<meta charset="utf-8">
</head>
<body>
Hello<br>
<div id="target"><script src="http://127.0.0.1:8080/testPlace/jsfile.js" type="text/javascript"></script></div>
<script>
    //That Script which here I removed it to take less space in answer
</script>
OK MAN!</body>
</html>

什么是第三方javascript文件?

如果是Google Maps JavaScript API v3,那么请确保在脚本URL中包含"&callback=your_init_funct"。然后,一旦地图库被加载,它将调用'your_init_funct',这样你就可以开始显示地图了。

另一个解决方案是bezen.domwrite.js,它可以在这里:http://bezen.org/javascript/index.html

演示:http://bezen.org/javascript/test/test-domwrite.html

是的,文档。不能从异步加载的脚本中调用Write,因为它与文档是分离的,所以不能写入。

您可以看到google maps api在这里使用的方法来解决这个问题。所以,有可能你的一些第三方脚本,你还没有命名,可以有类似的回调模式实现。

https://developers.google.com/maps/documentation/javascript/examples/map-simple?hl=EN

<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #map {
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
var map;
function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -34.397, lng: 150.644},
    zoom: 8
  });
}
    </script>
    <script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
        async defer></script>
  </body>
</html>