资源加载跟踪

浏览器允许我们跟踪外部资源的加载情况

  • 脚本 script
  • iframe
  • 图片等

一共涉及两个事件

  1. onload 事件
  2. onerror 事件

加载脚本

当我们使用动态脚本引入外部资源时,如果我们想要在脚本加载并执行完成后调用其中的函数,可以这么做

javascript
1let script = document.createElement('script')
2
3// 可以从任意域(domain),加载任意脚本
4script.src = 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js'
5document.head.append(script)
6
7script.onload = function () {
8  // 该脚本创建了一个变量 "_"
9  alert(_.VERSION) // 显示库的版本
10}
11//如果加载失败,则会进入这个函数
12script.onerror = function () {
13  alert('Error loading ' + this.src) // Error loading
14}

如果是我们自己写的脚本,则可以使用module的方式来引入即可,这里列举外部引入的脚本

重要:

onload/onerror 事件仅跟踪加载本身。

在脚本处理和执行期间可能发生的 error 超出了这些事件跟踪的范围。也就是说:如果脚本成功加载,则即使脚本中有编程 error,也会触发 onload 事件。如果要跟踪脚本 error,可以使用 window.onerror 全局处理程序。

加载其他资源

load 和 error 事件也支持加载其他资源,基本上适用于所有有src属性的资源,比如下面是加载图片

javascript
1let img = document.createElement('img')
2img.src = 'https://js.cx/clipart/train.gif'
3
4img.onload = function () {
5  alert(`Image loaded, size ${img.width}x${img.height}`)
6}
7
8img.onerror = function () {
9  alert('Error occurred while loading image')
10}

对于 iframe 来说,iframe 加载完成后会触发 iframe.onload 事件,无论成功还是出现 error

跨域脚本策略

script标签的 src一般会越过跨域问题,在 script请求对方资源时,会有以下细节

  • script请求资源时,request header 不会带有 origin 头
  • script请求资源时,如果对方的脚本出现 error,那么通过本方的window.onerror事件没办法获取到详细的 error 信息

以下代码就是获取对方脚本资源,但是却打不出详细的 error 信息

html
1<script>
2  window.onerror = function (message, url, line, col, errorObj) {
3    alert(`${message}\n${url}, ${line}:${col}`)
4  }
5</script>
6<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

这是因为这个 error 信息来自其他源。

要允许跨域访问,于是script也需要具有 crossorigin特性,并且远程服务器也需要提供 header 告诉浏览器运行跨域

这里有两个属性可以设置

  • crossorigin="anonymous"匿名访问——如果对方的响应中的 header中的Access-Control-Allow-Origin 带有*或者我们的 origin,则允许访问。浏览器不会授权信息和 cookie 发送给远程服务器
  • crossorigin="use-credentials"使用资格——如果对方的响应中的header中的Access-Control-Allow-Origin带有我们的源并且Access-Control-Allow-Credentials: true.则允许访问。且浏览器会授权信息和 cookie 发送给远程服务器

常见情况是不会给对方发送 cookie的,我们只是需要对方的错误信息,所以我们将上面的代码加上crossorigin="anonymous"

属性,这时候就可以看到完整的错误信息了

html
1<script>
2  window.onerror = function (message, url, line, col, errorObj) {
3    alert(`${message}\n${url}, ${line}:${col}`)
4  }
5</script>
6<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

小结

  1. 图片 img 外部样式 iframe 等资源都可以通过 load和 error事件跟踪它们的加载情况
  2. iframe 不管加载成功或者失败都只会触发 load 事件,这可能是处于历史原因
  3. script 标签在加载时也可能需要跨域,这时候可以设置 crossorigin属性