我目前正在建立一个自己的SPA框架。我只是好奇,有些事情在后台运作。
假设我想从服务器动态导入脚本。
我目前使用的方法是在头部包含一个脚本标记,“async”属性设置为true。这样的事情。
for (let requiredScript of requiredScripts){
var $head = document.getElementsByTagName('head')[0];
var $script = document.createElement('script');
$script.src = requiredScript;
$script.async = true;
$script.onload = function(){
callback();
}
$head.appendChild($script);
}
这如何在浏览器中正常工作?我读到浏览器为head标签中的每个脚本生成一个新线程,当它们加载时,它们会对它们产生影响。 (我也可以使用延迟属性,但这并不重要。)
这(如果它可以正常工作),很棒。语法很难看,但它很有效。有一点缺点:我无法为这些请求显式设置标头。例如,我想为每个受限资源请求添加一个JWT令牌,我不能,我必须使用ajax调用。但这不是这个问题的一部分。
所以,加载我的资源的第二种方式(第三种方式,ES6导入,但我现在不打算使用它)是通过AJAX调用加载我的资源。但是从XMLHttp请求的本质来说,我只得到一个字符串,或者可能是JSON,而不是脚本,所以我必须调用eval(),这既缓慢又不安全。
但是让我们回答这个问题。 脚本标记中的资源调用究竟是什么?它与xmlhttp请求(或ajax调用)有何不同?在解析html文件并使用脚本标记评估行时,浏览器究竟做了什么?我可以将javascript文件导入为二进制文件,并使浏览器只执行它吗? (eval()更快更安全的选项)。 我希望能够完全控制和理解我正在做的事情,但我感到非常困惑,无法在这个主题上找到正确的答案。
每一个解释(甚至是一个有用的链接)都会有很大的吸引力。
答案 0 :(得分:0)
脚本标记中的资源调用究竟是什么?
<script>
标记只是告诉浏览器在脚本标记中的URL上执行http GET,然后将生成的文本发送到Javascript解释器以进行解析和运行。您可以在浏览器调试器中查看网络选项卡,以查看它正在执行的确切http GET操作。
它与xmlhttp请求(或ajax调用)有何不同?
两者中的初始请求都是http GET,因此完全没有区别。 xmlhttp请求受到同源安全保护的约束。 <script>
标记不受同源保护,因此可以从任何地方加载脚本。
在解析html文件和评估时,浏览器究竟做了什么 带脚本标记的行?
我认为这是上面描述的(http GET,然后结果传递给JS解析器)。
我可以将javascript文件作为二进制文件导入,并只使用浏览器 执行它? (更快更安全的选择,即eval())
不,不是真的。首先,JS文件不是二进制文件,而是文本。对于预解析/编译的二进制Javascript,还没有采用并广泛实现的标准。您可以阅读有关Emscripten和Asm.js的内容,了解在这方面正在开展的一些工作,不过Emscripten确实将其他语言代码转换为JS。
当你说“比eval()
更安全”时,你必须描述你想要保护的问题。加载脚本标记或使用Ajax加载脚本然后在其上调用eval()
将在全局上下文中评估脚本,并具有广泛的功能来覆盖您的页面。
您可以通过使用XMLHttpRequest来检索脚本文本来自己控制加载和执行(如果不是跨源请求),然后您可以通过将文本插入脚本标记或通过调用来自行解析和执行它eval()
就可以了。除非你想在执行之前以某种方式修改或验证脚本,否则自己手动加载它确实没有任何好处。