资源加载:onload,onerror

浏览器允许我们跟踪外部资源的加载 —— 脚本,iframe,图片等。

这里有两个事件:

  • onload —— 成功加载,

  • onerror —— 出现 error。

加载脚本

假设我们需要加载第三方脚本,并调用其中的函数。

我们可以像这样动态加载它:

let script = document.createElement('script');
script.src = "my.js";document.head.append(script);

……但如何运行在该脚本中声明的函数?我们需要等到该脚本加载完成,之后才能调用它。

对于我们自己的脚本,可以使用 JavaScript module,但是它们并未被广泛应用于第三方库。

script.onload

我们的得力助手是 load 事件。它会在脚本加载并执行完成时触发。

例如:

let script = document.createElement('script');// 可以从任意域(domain),加载任意脚本
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);script.onload = function() {// 该脚本创建了一个变量 "_"alert( _.VERSION ); // 显示库的版本
};

因此,在 onload 中我们可以使用脚本中的变量,运行函数等。

……如果加载失败怎么办?例如,这里没有这样的脚本(error 404)或者服务器宕机(不可用)。

script.onerror

发生在脚本加载期间的 error 会被 error 事件跟踪到。

例如,我们请求一个不存在的脚本:

let script = document.createElement('script');
script.src = "https://example.com/404.js"; // 没有这个脚本
document.head.append(script);script.onerror = function() {alert("Error loading " + this.src); // Error loading https://example.com/404.js
};

请注意,在这里我们无法获取更多 HTTP error 的详细信息。我们不知道 error 是 404 还是 500 或者其他情况。只知道是加载失败了。

注意:onload/onerror 事件仅跟踪加载本身

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

其他资源

loaderror 事件也适用于其他资源,基本上(basically)适用于具有外部 src 的任何资源。

例如:

let img = document.createElement('img');
img.src = "https://js.cx/clipart/train.gif"; // (*)img.onload = function() {alert(`Image loaded, size ${img.width}x${img.height}`);
};img.onerror = function() {alert("Error occurred while loading image");
};

但是有一些注意事项:

  • 大多数资源在被添加到文档中后,便开始加载。但是 <img> 是个例外。它要等到获得 src (*) 后才开始加载。

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

这是出于历史原因。

跨源策略

这里有一条规则:来自一个网站的脚本无法访问其他网站的内容。例如,位于 https://facebook.com 的脚本无法读取位于 https://gmail.com 的用户邮箱。

或者,更确切地说,一个源(域/端口/协议三者)无法获取另一个源(origin)的内容。因此,即使我们有一个子域,或者仅仅是另一个端口,这都是不同的源,彼此无法相互访问。

这个规则还影响其他域的资源。

如果我们使用的是来自其他域的脚本,并且该脚本中存在 error,那么我们无法获取 error 的详细信息。

例如,让我们使用一个脚本 error.js,该脚本只包含一个(错误)函数调用:

// ???? error.js
noSuchFunction();

现在从它所在的同一个网站加载它:

<script>
window.onerror = function(message, url, line, col, errorObj) {alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="/article/onload-onerror/crossorigin/error.js"></script>

我们可以看到一个很好的 error 报告,就像这样:

Uncaught ReferenceError: noSuchFunction is not defined
https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1

现在,让我们从另一个域中加载相同的脚本:

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

此报告与上面那个示例中的不同,就像这样:

Script error.
, 0:0

error 的详细信息可能因浏览器而异,但是原理是相同的:有关脚本内部的任何信息(包括 error 堆栈跟踪)都被隐藏了。正是因为它来自于另一个域。

为什么我们需要 error 的详细信息?

因为有很多服务(我们也可以构建自己的服务)使用 window.onerror 监听全局 error,保存 error 并提供访问和分析 error 的接口。这很好,因为我们可以看到由用户触发的实际中的 error。但是,如果一个脚本来自于另一个源(origin),那么正如我们刚刚看到的那样,其中没有太多有关 error 的信息。

对其他类型的资源也执行类似的跨源策略(CORS)。

要允许跨源访问,<script> 标签需要具有 crossorigin 特性(attribute),并且远程服务器必须提供特殊的 header。

这里有三个级别的跨源访问:

  1. crossorigin 特性 —— 禁止访问。

  2. crossorigin="anonymous" —— 如果服务器的响应带有包含 * 或我们的源(origin)的 header Access-Control-Allow-Origin,则允许访问。浏览器不会将授权信息和 cookie 发送到远程服务器。

  3. crossorigin="use-credentials" —— 如果服务器发送回带有我们的源的 header Access-Control-Allow-OriginAccess-Control-Allow-Credentials: true,则允许访问。浏览器会将授权信息和 cookie 发送到远程服务器。

你可以在 Fetch:跨源请求 一章中了解有关跨源访问的更多信息。这一章描述了用于网络请求的 fetch 方法,但策略是完全相同的。

诸如 "cookie" 之类的内容超出了本章的范围,但你可以在 Cookie,document.cookie 一章学习它们。

在我们的示例中没有任何跨源特性(attribute)。因此,跨源访问被禁止。让我们来添加它吧。

我们可以在 "anonymous"(不会发送 cookie,需要一个服务器端的 header)和 "use-credentials"(会发送 cookie,需要两个服务器端的 header)之间进行选择。

如果我们不关心 cookie,那么可以选择 "anonymous"

<script>
window.onerror = function(message, url, line, col, errorObj) {alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script *!*crossorigin="anonymous"*/!* src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

现在,假设服务器提供了 Access-Control-Allow-Origin header,一切都正常。我们有了完整的 error 报告。

总结

图片 <img>,外部样式,脚本和其他资源都提供了 loaderror 事件以跟踪它们的加载:

  • load 在成功加载时被触发。

  • error 在加载失败时被触发。

唯一的例外是 <iframe>:出于历史原因,不管加载成功还是失败,即使页面没有被找到,它都会触发 load 事件。

readystatechange 事件也适用于资源,但很少被使用,因为 load/error 事件更简单。

作业题

先自己做题目再看答案。

使用回调函数加载图片

重要程度:⭐️⭐️⭐️⭐️

通常,图片在被创建时才会被加载。所以,当我们向页面中添加 <img> 时,用户不会立即看到图片。浏览器首先需要加载它。

为了立即显示一张图片,我们可以“提前”创建它,像这样:

let img = document.createElement('img');
img.src = 'my.jpg';

浏览器开始加载图片,并将其保存到缓存中。以后,当相同图片出现在文档中时(无论怎样),它都会立即显示。

创建一个函数 preloadImages(sources, callback),来加载来自数组 source 的所有图片,并在准备就绪时运行 callback

例如,这段代码将在图片加载完成后显示一个 alert

function loaded() {alert("Images loaded")
}preloadImages(["1.jpg", "2.jpg", "3.jpg"], loaded);

如果出现错误,函数应该仍假定图片已经“加载完成”。

换句话说,当所有图片都已加载完成,或出现错误输出时,将执行 callback

例如,当我们计划显示一个包含很多图片的可滚动图册,并希望确保所有图片都已加载完成时,这个函数很有用。

在源文档中,你可以找到指向测试图片的链接,以及检查它们是否已加载完成的代码。它应该输出 300

答案:

  1. 为每个资源创建 img

  2. 为每个图片添加 onload/onerror

  3. onloadonerror 被触发时,增加计数器。

  4. 当计数器值等于资源值时 —— 我们完成了:callback()

function preloadImages(sources, callback) {let counter = 0;function onLoad() {counter++;if (counter == sources.length) callback();}for(let source of sources) {let img = document.createElement('img');img.onload = img.onerror = onLoad;img.src = source;}
}

现代 JavaScript 教程:开源的现代 JavaScript 从入门到进阶的优质教程。React 官方文档推荐,与 MDN 并列的 JavaScript 学习教程。

在线免费阅读:https://zh.javascript.info


看完三件事

如果你觉得本文对你有帮助,我想请你帮个忙:

  1. 转发本文点赞或者点个「在看」,是对我最大的认可和支持;

  2. 关注公众号「技术漫谈」,订阅更多精彩内容,获取更多学习资料;

  3. 公众号后台回复「加群」,加入算法和技术交流群,与更多读者交流。


近期精彩回顾

图解浏览器:架构演进、渲染流程和垃圾回收等

漫画 | Bug 是如何产生的?

【JS】1.1w字 | 初中级前端 JS 自测清单 - 2

Create React App 脚手架实现原理和核心思想

Vue CLI 是如何实现的 —— 终端命令行工具篇

自动生成组件代码—— Vue CLI 插件开发实战

浏览器专题系列 —— Web 安全问题和解决方案

浏览器专题系列 —— 本地存储汇总分析

赏个“赞”或“在看”呗~ 

JavaScript 页面资源加载:onload,onerror相关推荐

  1. JavaScript 页面资源加载方法onload,onerror总结

    资源加载:onload,onerror 浏览器允许我们跟踪外部资源的加载 -- 脚本,iframe,图片等. 这里有两个事件: onload -- 成功加载, onerror -- 出现 error. ...

  2. 浏览器页面资源加载过程与优化

    评价页面性能好坏的核心之一就是页面的加载速度,而页面加载速度的关键就是页面资源的加载.本文将从浏览器浏览器页面资源加载过程展开分析,来引出页面关键请求路径的概念,并给出如何优化该关键请求路径的一些方法 ...

  3. 使用 PreloadPrefetch 优化前端页面的资源加载

    对于前端页面来说,静态资源的加载对页面性能起着至关重要的作用.本文将介绍浏览器提供的两个资源指令-preload/prefetch,它们能够辅助浏览器优化资源加载的顺序和时机,提升页面性能. 一.从一 ...

  4. html资源加载前触发事件,jquery页面加载时触发ready()事件

    ready()事件类似于onLoad()事件,但前者只要页面的DOM结构加载后便触发,而后者必须在页面全部元素加载成功才触发,ready()可以写多个,按顺序执行.此外,下列写法是相等的: $(doc ...

  5. 页面载入-(dom、css、图片 等资源 加载完成) 执行

    1. // 页面载入-(dom.css.图片 等资源 加载完成) 执行 window.onload=function(){console.log("aaa"); }window.o ...

  6. google android广告异步加载,javascript 广告后加载,加载完页面再加载广告

    先加载完页面再加载广告的原理: 网页打开的顺序都是按页面从上到下的顺序加载完成的,所以要想使广告不影响页面打开速度,就要等页面全部打开完成后,再加载JS代码.等页面加载完再加载广告其实就是将广告的 J ...

  7. html 判断页面加载完成,Javascript判断页面是否加载完成

    很多时候我们在使用document.getElementById的时候直接在script标签中获取对象,然后使用,此时程序会出现该对象为undefined. var dom=document.getE ...

  8. 前端性能优化学习 08 资源加载优化

    图片延迟加载 什么是延迟加载 首先来想象一个场景,当浏览一个内容丰富的网站时,比如电商的商品列表页.主流视频网站的节目列表等,由于屏幕尺寸的限制,每次只能查看到视窗中的那部分内容,而要浏览完页面所包含 ...

  9. html视频资源加载出错处理,如何处理前端异常

    错误类型数据 错误类型主要是运行过程中的前端报错,Javascript原生提供Error构造函数,所有抛出的错误都是它的实例.Error实例对象有以下属性属性描述message错误提示信息 name错 ...

最新文章

  1. android异常相机处理器,Cordova Android Camera-提供非法参数异常
  2. 图像条纹检测 python_【连载4.5】特征检测技术研究面向强反射表面的多传感器三维检测技术研究...
  3. mysql汉字占几个字符_mysql和oracle的一个汉字占几个字符
  4. 《JavaScript面向对象精要》——1.9 总结
  5. javaWeb服务详解(含源代码,测试通过,注释) ——applicationContext-dao.xml
  6. c语言动态内存分配数组,【C】动态内存分配
  7. 写出表格的结构html,一个面试题,根据json结构生成html表格
  8. 时时流量查看工具-ifsta,nload,iftop
  9. HashTable 基础
  10. 20165323 第五周学习总结
  11. ubuntu 默认防火墙安装、启用、查看状态
  12. ERP咨询顾问是怎么炼成的?
  13. UVA10735 Euler Circuit题解
  14. ai转型指南_穿越AI转型的转折点
  15. 华为交换机S3700基本配置
  16. Android 学习资料收集
  17. 小米4A 32电视通过TTL方式ROOT的方法
  18. 计算字符串相似度算法——Levenshtein
  19. r730 raid5 linux 驱动,DELL R720安装REDHAT5.1 RAID驱动问题
  20. 介数中心度与紧密中心度_将开发团队与技术紧密结合的6种方法

热门文章

  1. 银联电子支付 php chinapay
  2. 商用在线客服软件测试报告
  3. 软件架构发展历程分享
  4. Unity 3D模型展示框架篇之框架运用
  5. 源生的html属性js,使用源生JS自定义动画(支持多个属性)
  6. 华为鸿蒙系统什么时候出售,华为智慧屏搭载鸿蒙预约发售 华为鸿蒙系统手机什么时候上市 华为鸿蒙系统是什么系统?...
  7. 485之modbus通讯协议学习笔记
  8. python readline读文件,并且将其转化为数字形式时:ValueError: could not convert string to float:
  9. 51Nod1631 小鲨鱼在51nod小学
  10. 北醒激光雷达模组 资料汇总