首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JavaScript 页面资源加载方法onload,onerror总结

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

作者头像
winty
发布于 2021-03-11 04:06:34
发布于 2021-03-11 04:06:34
4.8K02
代码可运行
举报
文章被收录于专栏:前端Q前端Q
运行总次数:2
代码可运行

资源加载:onload,onerror

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

这里有两个事件:

  • onload —— 成功加载,
  • onerror —— 出现 error。

加载脚本

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let script = document.createElement('script');
script.src = "my.js";

document.head.append(script);

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

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

script.onload

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

例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 事件跟踪到。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 的任何资源。

例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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,该脚本只包含一个(错误)函数调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ? error.js
noSuchFunction();

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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 报告,就像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Uncaught ReferenceError: noSuchFunction is not defined
https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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>

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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"

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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> 时,用户不会立即看到图片。浏览器首先需要加载它。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let img = document.createElement('img');
img.src = 'my.jpg';

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function loaded() {
  alert("Images loaded")
}

preloadImages(["1.jpg", "2.jpg", "3.jpg"], loaded);

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

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

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

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

答案:

  1. 为每个资源创建 img
  2. 为每个图片添加 onload/onerror
  3. onloadonerror 被触发时,增加计数器。
  4. 当计数器值等于资源值时 —— 我们完成了:callback()
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端Q 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从零开始搭建前端数据监控系统(二)-前端性能监控方案调研
1. 业界案例 目前前端性能监控系统大致为分两类:以GA为代表的代码监控和以webpagetest为代表的工具监控。 代码监控依托于js代码并部署到需监控的页面,手动计算时间差或者使用浏览器的的API进行数据统计。 影响代码监控数据的因素有以下几种: 浏览器渲染机制; 浏览器对API的实现程度,比如performance API; 工具监控不用将统计代码部署到页面中,一般依托于虚拟机。以webpageTest为例,输入需统计的url并且选择运行次url的浏览器版本,webpageTest后台虚拟机对url进
寒月十八
2018/01/30
2.6K0
从零开始搭建前端数据监控系统(二)-前端性能监控方案调研
一文带你了解跨域的前因后果和解决方案
在了解跨域之前,我们必须要了解一下同源策略。 跨域问题其实就是浏览器的同源策略造成的。
用户6297767
2023/12/23
5280
一文带你了解跨域的前因后果和解决方案
前端错误捕获方案总结
本文主要摘抄自:https://juejin.cn/post/7172072612430872584#heading-10,主要用来记录和学习,也推荐大家看看原博主的文章。
蓓蕾心晴
2022/12/30
1.8K0
前端错误捕获方案总结
前端错误监控解决方案
在当今的互联网时代,web开发越来越受到重视,网页能实现的功能也越来多,之前只能在客户端上运行的程序,也逐渐转到网页上,面对成千上万的用户,出现错误的概率也是越来大。项目上线前期的粒度较大的错误我们都会在自测和QA测试中发现,然而上线之后的错误就不是那么好发现。同时移动端的开发也面临着一个问题就是不好调试,所以web开发的错误监控是一个非常有用的措施。前端的错误监控有哪些方法呢。
挥刀北上
2019/07/19
8240
如何优雅处理前端异常?
对于 JS 而言,我们面对的仅仅只是异常,异常的出现不会直接导致 JS 引擎崩溃,最多只会使当前执行的任务终止。
grain先森
2019/03/29
2.3K0
如何优雅处理前端异常?
【干货】加强 web 静态资源安全方法之SRI
我们通常会用CSP加强站点JS资源的执行限制,有效降低XSS攻击;我们通过HTTPS链接加密资源,减少站点资源劫持风险等等大量的前端安全方案。但你可能还没听说 Subresource Integrity (SRI) 子资源完整性校验。 本文将带你了解SRI是什么,能解决哪些安全风险,如何快速接入。同时,使用它又会带来哪些问题,以及浏览器的支持情况如何。 什么是SRI ? SRI 是 Subresource Integrity 的缩写,可翻译为:子资源完整性,它也是由 Web 应用安全工作组(Web Ap
腾讯NEXT学位
2018/12/04
11K0
【干货】加强 web 静态资源安全方法之SRI
Javascript跨域
如果协议,端口(如果指定了一个)和主机对于两个页面是相同的,则两个页面具有相同的源。
菜的黑人牙膏
2019/01/21
1.1K0
面试官:介绍下回调
JavaScript主机环境提供了许多函数,允许您调度异步操作。换句话说,我们现在开始的行动,但它们会在稍后结束。
公众号---人生代码
2021/02/24
5880
面试官:介绍下回调
web前端监控的三个方面探讨
以 init 为程序的入口,代码中所有同步执行出现的错误都会被捕获,这种方式也可以很好的避免程序刚跑起来就挂。
smy
2018/08/01
1.2K0
web前端监控的三个方面探讨
2024全网最全面及最新且最为详细的网络安全技巧 七之 XSS漏洞典例分析EXP以及 如何防御和修复(1)———— 作者:LJS
我们先分析代码,正则表达式过滤了什么,()`\并且是全局过滤,这样一来,不能使用()就对弹窗很不利,那么我首先想到的办法就是编码,利用编码绕过
盛透侧视攻城狮
2024/10/21
4260
2024全网最全面及最新且最为详细的网络安全技巧 七之 XSS漏洞典例分析EXP以及 如何防御和修复(1)———— 作者:LJS
DVWA 1.10 High等级的CSRF另类通关法
由于使用了不可猜测到的token,所以我们首先想到的思路,就是找一个XSS漏洞来配合,先通过XSS获得token之后修改密码。
FB客服
2019/05/21
1K0
前端 JavaScript 错误分析实践
在平日的工作中前端 badjs 是一个比较常见的问题, badjs 除了我们自身业务 js 脚本里比较明显的报错外还有依赖其他资源的一些报错,对于自身业务 js 里出现的错误很容易进行定位并修复,但对于依赖资源的错误即常见的 script error (外部 js、接口错误)定位就没那么容易了。
WecTeam
2019/12/16
1.1K0
前端 JavaScript 错误分析实践
JavaScript异常如何处理
在前端的开发工作当中,我们对于异常的处理可能关注的不是太多,因为js有基本的异常处理能力,很多错误会直接抛出来,打开控制台就能看到。但是如果因为异常导致网站卡死,甚至崩溃无法继续进行下去,对于用户的体验是相当差的,我们应该及时的捕获这些异常,对用户进行一些简要的温馨提示,并将异常进行及时的上报,以便于快速解决。
OECOM
2020/07/02
1.8K0
JavaScript异常如何处理
再谈DOMContentLoaded与渲染阻塞—分析html页面事件与资源加载
浏览器的多线程中,有的线程负责加载资源,有的线程负责执行脚本,有的线程负责渲染界面,有的线程负责轮询、监听用户事件。
周陆军
2018/05/22
5.4K0
白帽赏金平台XSS漏洞模糊测试有效载荷最佳集合 2020版
该备忘清单可用于漏洞猎人,安全分析,渗透测试人员,根据应用的实际情况,测试不同的payload,并观察响应内容,查找web应用的跨站点脚本漏洞,共计100+条xss漏洞测试小技巧。
瓦都剋
2020/12/17
10.1K0
消费者怎么看待 then, catch, finally
昨天讲了关于 Promise 的理解,有人在下面评论说要我出关于源码的解析,能力有限只能循序渐进了,我们还是先把基础的搞明白,再逐步深入。
公众号---人生代码
2021/03/16
1.1K0
通过DVWA学习XSS
简介 这篇文章通过 dvwa 简单研究了三种类型的 xss,并且讲述了如何利用 xss 获取目标网站用户的 cookie。 dvwa反射型xss 测试环境 一台 win200
奶糖味的代言
2018/04/16
5.8K0
通过DVWA学习XSS
源码解析-url状态检测神器ping-url
前言 ping-url是我最近开源的一个小工具,这篇文章也是专门写它设计理念的科普文。 为什么会做这个ping-url开源工具呢? 起因是:本小哥在某天接到一个特殊的需求,要用前端的方式判断任意一个u
我是leon
2019/08/28
2K0
前端安全 — 浅谈JavaScript拦截XSS攻击
XSS/跨站脚本攻击,是一种代码注入网页攻击,攻击者可以将代码植入到其他用户都能访问到的页面(如论坛、留言板、贴吧等)中。
天存信息
2021/06/15
5.2K0
前端安全 — 浅谈JavaScript拦截XSS攻击
优秀博客文章 | javascript跨域方法总结
最近面试问的挺多的一个问题,就是JavaScript的跨域问题。在这里,对跨域的一些方法做个总结。由于浏览器的同源策略,不同域名、不同端口、不同协议都会构成跨域;但在实际的业务中,很多场景需要进行跨域传递信息,这样就催生出多种跨域方法。
用户1467662
2019/04/19
6200
优秀博客文章 | javascript跨域方法总结
相关推荐
从零开始搭建前端数据监控系统(二)-前端性能监控方案调研
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档