JavaScript异步机制

来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html

JavaScript是单线程异步执行的,单线程意味着代码在任务队列中会按照顺序一个接一个的执行。异步代表JavaScript代码在任务队列中的顺序并不完全等同于代码的书写顺序,比如事件绑定、Ajax、setTimeout()等任务的发生时间是“不可被预期”的。

页面加载时,JavaScript引擎会顺序执行页面上所有JavaScript代码,优先执行同步代码。而异步代码由事件触发引擎按照“事件发生”的顺序添加到JavaScript引擎的任务队列中,待所有同步代码执行结束后,JavaScript引擎会按照任务队列中的顺序来执行异步代码。

知乎上的一段回答:

JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序。

浏览器的内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器至少实现三个常驻线程:JavaScript引擎线程GUI渲染线程浏览器事件触发线程

  1. JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JavaScript线程在运行JavaScript程序。
  2. GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。但需要注意,GUI渲染线程与JavaScript引擎是互斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JavaScript引擎空闲时立即被执行。
  3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待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。

转载于:https://www.cnblogs.com/simpul/p/11020230.html

前端知识点回顾之重点篇——JavaScript异步机制相关推荐

  1. 前端知识点回顾之重点篇——CORS

    CORS(cross origin resource sharing)跨域资源共享 来源:http://www.ruanyifeng.com/blog/2016/04/cors.html 它允许浏览器 ...

  2. 前端知识点回顾——HTML,CSS篇

    前端知识点回顾篇--是我当初刚转行为了面试而将自己学过的前端知识整理成的一份笔记,个人目的性很强,仅供参考. doctype 有什么用 doctype是一种标准通用标记语言的文档类型声明,目的是告诉标 ...

  3. 一篇需要膜拜的文篇--Javascript异步编程模型进化(转)

    要我能用得这么熟, 那前端出师了哈. http://foio.github.io/javascript-asyn-pattern/ 改天一个一个亲测一下. Javascript语言是单线程的,没有复杂 ...

  4. 马蹄疾 | 详解 JavaScript 异步机制及发展历程(万字长文)

    本文从Event Loop.Promise.Generator.async await入手,系统的回顾 JavaScript 的异步机制及发展历程. 需要提醒的是,文本没有讨论 nodejs 的异步机 ...

  5. html js异步绑定,JavaScript异步机制介绍

    异步就是代码执行的顺序,并不是按照从上到下的顺序一次性执行,而是在不同的时间段执行,一部分代码在"未来执行".本文就来为大家介绍一下JavaScript中的异步机制. 单线程异步执 ...

  6. 前端面试回顾(1)---javascript的面向对象

    前言 前一阵面试,过程中发现问到一些很基础的问题时候,自己并不能很流畅的回答出来.或者遇到一些基础知识的应用,由于对这些点理解的不是很深入,拿着笔居然什么都写不出来,于是有了回顾一下这些基础知识的想法 ...

  7. html5主要是针对哪方面行优化,前端知识点总结(HTML篇)

    ie的某些兼容性问题 IE的兼容性问题 doctype的作用 答案:doctype告诉浏览器它使用了什么文档类型.它指出阅读程序应该用什么 规则集来解释文档中的标记.XHTML中有三种,包括过度型.严 ...

  8. Flask知识点回顾以及重点内容

    1. HTTP通信与Web框架 1.1 流程 客户端将请求打包成HTTP的请求报文(HTTP协议格式的请求数据) 采用TCP传输发送给服务器端 服务器接收到请求报文后按照HTTP协议进行解析 服务器根 ...

  9. 细说JavaScript异步函数发展历程

    2019独角兽企业重金招聘Python工程师标准>>> < The Evolution of Asynchronous JavaScript >外文梳理了JavaScri ...

最新文章

  1. 43 inventory文件
  2. ReentrantLock与公平锁、非公平锁实现
  3. 阿里工程师养了只“二哈”,专治讨厌的骚扰电话
  4. 离开小米后 周受资将加入字节跳动担任CFO
  5. Python之函数进阶
  6. Oracle闪回技术(Flashback)
  7. 转:Oracle中的rownum不能使用大于的问题
  8. 《我也能做CTO之程序员职业规划》之十三:用凸透镜选择技术
  9. 简单web服务器的实现(C++)
  10. 阅读《21天学通Java》
  11. java所有单词汇总
  12. STM32用热敏电阻测温
  13. 箱线图2种画法-直接给出各个四分位值或者数据集
  14. 【Endnote】CNKI E-Study与Endnote 的参考文献题录互导
  15. dw中html网页如何加音乐播放器,在dreamweaver网页制作中插入音乐播放器详细参考...
  16. 商业银行vh是哪个银行的简称_各个银行的简称是什么?
  17. 2017中兴算法挑战赛(迪杰斯特拉)
  18. 微信群机器人微云助手微小云微信群淘客助手如何设置好券直播淘宝联盟优惠券自动群发
  19. matlab自带电机案例,MATLAB电机仿真精华50例,源代码
  20. Spark使用Java读Hive写入HBase

热门文章

  1. 测试驱动开发是否是一种强迫症?
  2. log4net按照不同的【LEVEL】级别输出到不同文件
  3. 转发:Hekaton:SQL Server集成的内存事务处理
  4. 解决读写Excel的第三方类库as3xls无法读取中文和写入中文的问题
  5. python之xlrd、xlwt学习
  6. cf1139D. Steps to One(dp)
  7. Selenium Python 解决 UnexpectedAlertPresentException
  8. 【转】WINDOWS消息响应,以及处理分派机制
  9. 解决“ORA-01036: 非法的变量名/编号“错误
  10. WordPress免费精美主题分享系列之简洁风格篇