前端知识点回顾之重点篇——JavaScript异步机制
JavaScript异步机制
来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html
JavaScript是单线程异步执行的,单线程意味着代码在任务队列中会按照顺序一个接一个的执行。异步代表JavaScript代码在任务队列中的顺序并不完全等同于代码的书写顺序,比如事件绑定、Ajax、setTimeout()等任务的发生时间是“不可被预期”的。
页面加载时,JavaScript引擎会顺序执行页面上所有JavaScript代码,优先执行同步代码。而异步代码由事件触发引擎按照“事件发生”的顺序添加到JavaScript引擎的任务队列中,待所有同步代码执行结束后,JavaScript引擎会按照任务队列中的顺序来执行异步代码。
知乎上的一段回答:
JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序。
浏览器的内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器至少实现三个常驻线程:JavaScript引擎线程,GUI渲染线程,浏览器事件触发线程。
- JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JavaScript线程在运行JavaScript程序。
- GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。但需要注意,GUI渲染线程与JavaScript引擎是互斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JavaScript引擎空闲时立即被执行。
- 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JavaScript引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeout、也可来自浏览器内核的其他线程如鼠标点击、Ajax异步请求等,但由于JavaScript的单线程关系所有这些事件都得排队等待JavaScript引擎处理(当线程中没有执行任何同步代码的前提下才会执行异步代码)。
setTimeout()
JavaScript引擎在执行setTimeout(fn, 10)时,一方面继续执行setTimeout(fn, 10)后面的同步代码,同时另一方面开始计时,在10ms之后将fn插入任务队列中。待所有同步代码执行结束后(JavaScript引擎空闲),依次任务队列中的异步代码。所以,setTimeout(fn, 10)并不能准确的在10ms之后执行,而是大于等于10ms。
console.log(1)
setTimeout(function () {console.log('a')}, 10);
setTimeout(function () {console.log('b')}, 0);
var sum = 0;
for (var i = 0; i < 1000000; i ++) {
sum += i;
}
console.log(sum);
setTimeout(function () {console.log('c');}, 0);
输出结果将会是
1
499999500000
b
a
c
代码执行的逻辑如图所示:

如果将for循环上限去掉一个0:
console.log(1)
setTimeout(function () {console.log('a')}, 10);
setTimeout(function () {console.log('b')}, 0);
var sum = 0;
for (var i = 0; i < 100000; i ++) {
sum += i;
}
console.log(sum);
setTimeout(function () {console.log('c');}, 0);
输出结果:
1
4999950000
b
c
a
两段代码的区别在于for循环执行的时间不同,第一段代码的for循环执行时间大于10ms,所以console.log('a')先被插入任务队列,等for循环执行结束后,console.log('c')才被插入任务队列。第二段代码的for循环执行时间小于10ms,所以console.log('c')先被插入任务队列。

setInterval()
setInterval()的执行方式与setTimeout()有不同。假如执行setInterval(fn, 10),则每隔10ms,定时器的事件就会被触发。与setTimeout()相同的是,如果当前没有同步代码在执行(JavaScript引擎空闲),则定时器对应的方法fn会被立即执行,否则,fn就会被加入到任务队列中。由于定时器的事件是每隔10ms就触发一次,有可能某一次事件触发的时候,上一次事件的处理方法fn还没有机会得到执行,仍然在等待队列中,这个时候,这个新的定时器事件就被丢弃,继续开始下一次计时。需要注意的是,由于JavaScript引擎这种单线程异步的执行方式,有可能两次fn的实际执行时间间隔小于设定的时间间隔。比如上一个定时器事件的处理方法触发之后,等待了5ms才获得被执行的机会。而第二个定时器事件的处理方法被触发之后,马上就被执行了。那么这两者之间的时间间隔实际上只有5ms。因此,setInterval()并不适合实现精确的按固定间隔的调度操作。
console.log(1)
var interval = setInterval(function () {
var date = new Date();
console.log(date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
}, 10);
var sum = 0;
for (var i = 0; i < 1000000; i ++) {
sum += i;
}
console.log(2);
// 清除定时器,避免卡死浏览器
setTimeout(function () {
clearInterval(interval);
}, 100);
输出结果:
1
2
12:32:236
12:32:240
12:32:251
12:32:262
可以看出,setInterval()前两次的间隔时间只有4ms。因为setInterval()第一次被触发后,里面的方法并没有马上被执行,而是等待同步代码执行结束后才被执行,这个过程用了6ms。所以当第一次方法执行过后4ms,第二次方法也被执行了。从setInterval()第二次被触发开始,后面几次的执行都没有被阻塞,所以间隔时间都在11ms左右。
总的来说,setTimeout()和setInterval()都不能满足精确的时间间隔。假如设定的时间间隔为10ms,则setTimeout(fn, 10)中的fn执行的时间间隔可能大于10ms,而setInterval(fn, 10)中fn执行的时间间隔可能小于10ms。
前端知识点回顾之重点篇——JavaScript异步机制的更多相关文章
- 前端知识点回顾之重点篇——AJAX
Ajax(Asynchronous JavaScript and XML) 这种技术就是无须刷新页面即可从服务器中取得数据,但不一定是XML数据.在原生方法上,Ajax技术的核心是XMLHttpReq ...
- 前端知识点回顾之重点篇——ES6的Promise对象
Promise Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大. 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异 ...
- 前端知识点回顾之重点篇——ES6的Iterator和Generator
Iterator 迭代器是一种接口.是一种机制. 为各种不同的数据结构提供统一的访问机制.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员). Iter ...
- 前端知识点回顾之重点篇——CSS中vertical align属性
来源:https://www.cnblogs.com/shuiyi/p/5597187.html 行框的概念 红色(line-height)为行框的顶部和底部,绿色(font-size)为字体的高度, ...
- 前端知识点回顾之重点篇——CSS中flex布局
flex布局 来源: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool 采用 Flex 布局的元素 ...
- 前端知识点回顾之重点篇——jQuery实现的原理
jQuery jQuery的实现原理 参考:https://blog.csdn.net/zhouziyu2011/article/details/70256659 外层沙箱和命名空间$ 为了避免声明了 ...
- 前端知识点回顾之重点篇——CORS
CORS(cross origin resource sharing)跨域资源共享 来源:http://www.ruanyifeng.com/blog/2016/04/cors.html 它允许浏览器 ...
- 前端知识点回顾之重点篇——ES6的async函数和module
async函数 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是 Generator 函数的语法糖 什么是语法糖? 意指那些没有给计算机语言添加新功能,而只是 ...
- 前端知识点回顾之重点篇——CSS中的BFC
BFC布局(Block Formatting Contexts) 来源:https://www.cnblogs.com/lzbk/p/6057097.html 块级格式化上下文是页面中的一块渲染区域, ...
随机推荐
- vue生命周期详细过程
- Outline 科学的上网
outline 官网:https://getoutline.org/zh-CN/home 下载 Outline 管理器 下载 Outline 客户端 配置浏览器代理
- 11.SpringMVC注解式开发-处理器方法的返回值
处理器方法的返回值 使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型 1.ModelAndView 2.String 3.void 4.自定义类型对象 1.返回Model ...
- idea控制台乱码修改
我的idea当前版本是2019.2.2 试了很多,只有这个有效果 工具类→HELP→Edit Custom VM OPtions中加 -Dfile.encoding=utf-8 然后重启IDEA 这个 ...
- 四:MVC之LINQ方法语法
linq 查询 有两种语法 ,前面我们说了一种,接下来说方法语法(我读着一直很绕口) 查询语法,方法语法 ------------------------以下文字都是复制-------------- ...
- 13_Redis_持久化
一:概述: Redis的高性能是山于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化. Redis支持两种方式的持久化,一 ...
- 2. An Array of Sequences
1. Overview of Built-In Sequences Container sequences: list, tuple, and collections.deque can hold i ...
- scala学习(4)---Array定长数组操作
ScalaArrayNote: https://www.jianshu.com/p/d906f00c05bf
- java线程基础巩固---如何实现一个自己的显式锁Lock
拋出synchronized问题: 对于一个方法上了同锁如果被一个线程占有了,而假如该线程长时间工作,那其它线程不就只能傻傻的等着,而且是无限的等这线程工作完成了才能执行自己的任务,这里来演示一下这种 ...
- Vue项目中的文件导出
项目中涉及到文件导出,分xml和excel导出.不同的文件导出格式不同,需要根据文件类型判断导出格式. exportAllData(val){ //全部导出 if(!val){ this.export ...