XMLHttprequest 与 "html tag" 资源加载

XMLHttp request vs "html tag" resource loading

我目前正在构建自己的小型 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 标记中的每个脚本生成一个新线程,当它们加载时,它们就会执行。 (我也可以使用 defer 属性,但这并不重要)。

这(如果它能像我预期的那样工作)太棒了。语法很丑陋,但它有效。有一点缺点:我不能为这些请求明确设置 header 。例如,我想为受限资源的每个请求添加一个 JWT 令牌,但我不能,而且我必须使用 ajax 调用。但这不是这个问题的一部分。

因此,第二种加载资源的方法(还有第三种方法,ES6 导入,但我暂时不会使用它)是通过 AJAX 调用加载我的资源。但是从 XMLHttp 请求的性质来看,我得到的只是一个字符串,或者 JSON,而不是一个脚本,所以我必须调用 eval(),这既慢又不安全。

但让我们开始讨论这个问题。 脚本标签中的资源调用到底是什么?它与 xmlhttp 请求(或 ajax 调用)有何不同?在解析 html 文件并评估带有脚本​​标记的行时,浏览器究竟做了什么?我可以将 javascript 文件作为二进制文件导入,并让浏览器执行它吗? (比 eval() 更快更安全的选项)。 我想完全控制和理解我正在做的事情,但我感到很困惑,找不到关于这个话题的正确答案。

我们将不胜感激任何解释(甚至是有帮助的 link)。

What exactly is a resource call in a script tag?

A <script> 标签只是告诉浏览器对脚本标签中的 URL 执行 http GET,然后将结果文本发送给 Javascript 解释器进行解析和运行。您可以在浏览器调试器中查看网络选项卡,以查看它正在执行的确切 http GET 操作。

How does it differ from xmlhttp request (or an ajax call)?

两者的初始请求都是 http GET,因此根本没有区别。 xmlhttp 请求受 same-origin 安全保护。 <script> 标签不受 same-origin 保护,因此它可以从任何地方加载脚本。

What exactly does browser do, when parsing html file and evaluating the line with script tag?

我认为这是上面描述的(一个http GET,然后将结果传递给JS解析器)。

Can I import a javascript file as a binary file, and make browser just execute it? (faster and safer option that eval())

不,不是真的。首先,JS 文件不是二进制的,它是文本。 pre-parsed/compiled 二进制 Javascript 还没有被采用和广泛实施的标准。您可以阅读 Emscripten and Asm.js 了解在这方面所做的一些工作,尽管 Emscripten 的目标确实是将其他语言代码转换为 JS。

当您说 "safer than eval()" 时,您必须描述您要避免的问题。加载脚本标签或使用 Ajax 加载脚本然后调用 eval() 将在全局上下文中评估脚本并将具有广泛的功能来破坏您的页面。

您可以通过使用 XMLHttpRequest 检索脚本文本来自行控制加载和执行(如果不是 cross-origin 请求),然后您可以通过将文本插入脚本来自行解析和执行它标记或通过在其上调用 eval()。除非你想在执行之前以某种方式修改或验证脚本,否则你自己手动加载它真的没有任何好处。