使用document.write是跨浏览器跨域同步加载脚本的唯一可能方式

Is using document.write the only possible way to load a script synchronously cross browser cross domain?

本文关键字:唯一 脚本 方式 加载 同步 write document 浏览器 使用      更新时间:2023-09-26

我想模仿这种行为:

<script src="console.log.1.js"></script>
<script>console.log(2)</script>
<script>console.log(3)</script>

退出:

1
2
3

这样做不起作用:

<script>
var x = document.createElement("script");
x.src = "console.log.1.js";
x.async = false;
x.defer = false;
document.body.appendChild(x);
console.log("2");
console.log("3");
</script>

它注销:

2
3
1

到目前为止,我找到的唯一方法是:

<script>
document.write("<scrip" + "t src='console.log.1.js'></scrip" + "t>");
</script>
<script>
console.log("2");
console.log("3");
</script>

这真的是在所有浏览器中强制同步加载外部脚本的唯一方法吗?为什么设置async=false,defer=false无效?

更新

仅供参考,如果有人想知道,以下文档.write初始工作(在Chrome中):

<script>
  // http://jsbin.com/avatiw logs "during"
  document.write('<scrip' + 't>console.log("before");document.write("<scrip" + "t src=''"http://jsbin.com/avatiw''"></scrip" + "t>");</scrip' + 't>');
  document.write('<scrip' + 't>console.log("after");</scrip' + 't>');
</script>

工作和注销:

"before"
"during"
"after"

是的,这是在页面解析期间强制加载脚本的唯一方法。或者至少,我愿意相信的唯一方法是跨浏览器运行良好。

如果你的剧本是这样的,我可以看到你的想法:

<script>
var x = document.createElement("script");
x.src = "console.log.1.js";
x.async = false;
x.defer = false;
document.body.appendChild(x);
</script>
<script><!-- note the new script element -->
console.log("2");
console.log("3");
</script>

因为理论上,当解析器命中script元素时,它会挂起所有内容(因为可能存在document.write语句)并调用JavaScript层。因此,您可能会认为,在body的末尾添加一个script元素会将其插入两者之间。

但是,通过appendChild添加script元素是根本不同的,它本质上是一种异步操作(在下载脚本时,您的代码会继续,而标记中的script元素除了deferasync属性外,情况并非如此)。我无法指出任何一个规范来说明原因,但你看到的行为正是我所期望的。与标记内联的script元素的处理有点特殊。

我们可以看出,问题出在下载上—至少在Chrome中—通过将结果与使用具有内联内容的CCD_ 11元素进行比较。

使用外部文件(实时副本|实时源):

<script>
console.log("before");
(function() {
    var s = document.createElement("script");
    s.src = "http://jsbin.com/avatiw"; // Logs the word "during"
    document.body.appendChild(s);
})();
</script>
<script>
console.log("after");
</script>

结果:

之前之后在
期间

使用内联脚本(实时副本|实时源代码—请注意,我没有尝试制作这种跨浏览器,它在Chrome和Firefox中工作,因为它们支持script元素上的text属性):

<script>
console.log("before");
(function() {
    var s = document.createElement("script");
    s.text = "console.log('during');";
    document.body.appendChild(s);
})();
</script>
<script>
console.log("after");
</script>

输出:

之前在期间在
之后

我实际上发现使用LazyLoad插件非常适合这个用例,即

if (typeof jQuery === 'undefined')
    LazyLoad.js('//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js', function() { 
        initialize(); 
    });
else
    initialize();