DOMContentLoaded事件中使用异步
概述
我在之前的博文(Performance面板看js加载)中提到过,如果利用监听DOMContentLoaded事件的方式来加载js是不能优化加载的,不能够替代jquery中的ready方法,原因是加载js的时候DOMContentLoaded事件还没有结束,自然不会发生页面渲染。
于是我去看jquery的源码,发现jquery里面用到了异步。我灵机一动,对啊,如果利用异步把监听DOMContentLoaded事件来加载的js放到任务队列进行延迟那不就行了。于是我分别用setTimeout和promise的方式来实现,竟然发生了不同的结果,真是令人惊喜。我把过程记录下来,供以后开发时参考,相信对其他人也有用。
使用setTimeout
代码如下:
//haha.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="haha.css">
</head>
<body>
<div id="haha"></div>
<script type="text/javascript" src="haha.js"></script>
</body>
</html>
//haha.css
div {
width: 800px;
height: 800px;
background-color: green;
font-size: 300px;
}
//haha.js
document.addEventListener("DOMContentLoaded", function(event) {
setTimeout(function() {
var a = 1;
while(a < 1000000000) {
a++;
}
}, 0);
});
通过js查看首屏渲染时间,发现非常完美的得到了优化,而且效果和jquery里面的ready方法达到的效果差不多,nice。
有一点需要提出的是,setTimeout可以只加一个参数,因为第二个参数delay有一个默认值,是0。所以上面的haha.js里面的代码可以改写如下:
document.addEventListener("DOMContentLoaded", function(event) {
setTimeout(function() {
var a = 1;
while(a < 1000000000) {
a++;
}
});
});
如果把执行代码变成一个模块,也能完美的嵌入到上面的代码里面。
使用Promise
自然的,那使用es6里面的promise呢?代码如下:
//haha.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="haha.css">
</head>
<body>
<div id="haha"></div>
<script type="text/javascript" src="haha.js"></script>
</body>
</html>
//haha.css
div {
width: 800px;
height: 800px;
background-color: green;
font-size: 300px;
}
//haha.js
document.addEventListener("DOMContentLoaded", function(event) {
const haha = new Promise( (resolve, reject)=>{
resolve();
} );
haha.then(function() {
var a = 1;
while(a < 1000000000) {
a++;
}
});
});
但是这一次,首屏时间没有得到优化。
通过复习一遍事件循环和任务队列的知识,可以解释这种情况:setTimeout是放在macrotask queue,这是这是浏览器实现的任务队列,并不是es6规范的任务队列;而promise是放在microtask queue里面,这才是es6规范的任务队列,每一个macrotask可以有许多小的microtask queue,并且当这次的macrotask执行完了之后再执行它下面的microtask queue,执行完microtask queue之后再执行下一个macrotask。
所以当我们用setTimeout的时候,会在DOMContentLoaded事件,渲染事件之后再加一个延迟事件,它是macrotask,与DOMContentLoaded事件和渲染事件同级,所以等DOMContentLoaded事件,渲染事件执行完之后才执行这个延迟的js。但是如果我们用promise的话,只会在DOMContentLoaded事件下的microtask queue塞入js,执行DOMContentLoaded事件完以后不会执行渲染事件,而是会先执行microtask queue。并且,通过看performance面板也可以看到,执行promise里面的代码的时候,DOMContentLoaded事件并没有结束,也是因为microtask queue是属于DOMContentLoaded事件的缘故。
其它
这个例子使我对macrotask queue和microtask queue的理解加深了许多!!!
DOMContentLoaded事件中使用异步的更多相关文章
- load/domContentLoaded事件、异步/延迟Js 与DOM解析
一.DOMContentLoaded 与 load事件 关于load和DOMContentLoaded事件,mdn对于它们是这样描述的: DOMContentLoaded mdn文档地址:https: ...
- JS中的异步以及事件轮询机制
一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...
- echarts异步数据加载(在下拉框选择事件中异步更新数据)
接触echarts 大半年了,从不会到熟练也做过不少的图表,隔了一段时间没使用这玩意,好多东西真心容易忘了.在接触echarts这期间也没有总结什么东西,今天我就来总结一下如何在echart中异步加载 ...
- C#中的异步调用及异步设计模式(三)——基于事件的异步模式
四.基于事件的异步模式(设计层面) 基于事件的C#异步编程模式是比IAsyncResult模式更高级的一种异步编程模式,也被用在更多的场合.该异步模式具有以下优点: · ...
- python:Asyncio模块处理“事件循环”中的异步进程和并发执行任务
python模块Asynico提供了管理事件.携程.任务和线程的功能已经编写并发代码的同步原语. 组成模块: 事件循,Asyncio 每个进程都有一个事件循环. 协程,子例程概念的泛化,可以暂停任务, ...
- ABP在领域事件中异步调用方法抛异常
在领域事件中调用UserRegistrationManager.RegisterAsync抛异常 Call UserRegistrationManager.RegisterAsync() throw ...
- 深入理解Javascript封装DOMContentLoaded事件
最近在写一个Javascript的框架,刚把DOMContentLoaded事件封装好,略带小兴奋,把开发过程中遇到的原理和兼容性问题做篇笔记,省的忘记到处找. 我们在写js代码的时候,一般都会添加w ...
- NodeJS中的异步I/O、事件驱动
nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...
- DOMContentLoaded事件
今天查看百度空间源代码,发现多了个util.js文件,打开看看.里面里面定义了addDOMLoadEvent.这是干什么用的? 仔细查看代码,发现在Mozilla添加了DOMContentLoaded ...
随机推荐
- Intersect交集Except差集Union并集实例
int[] oldArray = { 1, 2, 3, 4, 5 };int[] newArray = { 2, 4, 5, 7, 8, 9 };var jiaoJi = oldArray.Inter ...
- Eclipse中创建一个新的SpringBoot项目
在Eclipse中创建一个新的spring Boot项目: 1. 首先在Eclipse中安装STS插件:在Eclipse主窗口中点击 Help -> Eclipse Marketplace... ...
- 使用JavaMail发送邮件-从FTP读取图片并添加到邮件正文发送
业务分析: 最近工作需要,需要从FTP读取图片内容,添加到邮件正文发送.发送邮件正文,添加附件采用Spring的MimeMessageHelper对象来完成,添加图片也将采用MimeMessageHe ...
- netstat 常用参数总结
netstat 是一个机器网络查看工具 . 网络连接有哪些参数?
- H3C网络设备配置SSH登录
使用SSH+密码认证(基本SSH配置方法)注:在用户使用SSH登录交换机时,交换机对所要登录的用户使用密码对其进行身份验证生成RSA和DSA密钥对[H3C]public-key local creat ...
- 199. Binary Tree Right Side View 从右侧看的节点数
[抄题]: Given a binary tree, imagine yourself standing on the right side of it, return the values of t ...
- Linux驱动之定时器在按键去抖中的应用
机械按键在按下的过程中会出现抖动的情况,如下图,这样就会导致本来按下一次按键的过程会出现多次中断,导致判断出错.在按键驱动程序中我们可以这么做: 在按键驱动程序中我们可以这么做来取消按键抖动的影响:当 ...
- [网络流]Farm Tour(费用流
Farm Tour 题目描述 When FJ's friends visit him on the farm, he likes to show them around. His farm compr ...
- Python Day 3
阅读目录: 内容回顾: 变量(标识符)的命名规范: 常量: 格式化输入\输出: 注释: 基本数据类型: 运算符: ##内容回顾 1.语言的分类: -- 机器语言:直接编写0,1指令,直接能被硬件执行. ...
- python 实践项目
项目一:让用户输入圆的半径,告诉用户圆的面积 思路: 1.首先需要让用户输入一个字符串,即圆的半径 2.判断用户输入的字符串是否为数字 isalpha 3.求圆的面积需要调用到math模块,所以要导 ...