JavaScript同步、异步及事件循环
时间:2022-07-25
本文章向大家介绍JavaScript同步、异步及事件循环,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
同步、异步
JS是单线程的,每次只能做一件事情。像以下这种情况,代码会按顺序执行,这个就叫同步。
console.log(1);
console.log(2);
console.log(3);
以下代码会输出2、3、1,像这种不按顺序执行的,或者说代码执行中间有时间间隙的,叫异步。
setTimeout(() => {
console.log(1);
}, 0);
console.log(2);
console.log(3);
事件循环
一个浏览器通常有以下几个常驻的线程:
- 渲染引擎线程:该线程负责页面的渲染
- JS引擎线程:负责JS的解析和执行
- 定时触发器线程:处理定时事件,比如setTimeout, setInterval
- 事件触发线程:处理DOM事件
- 异步http请求线程:处理http请求
渲染线程和JS引擎线程是不能同时进行的。也就是说在执行代码时,渲染会挂起;渲染DOM时,代码也不会执行。 虽然JS是单线程,但是浏览器是多线程的,在遇到像setTimeout、DOM事件、ajax等这种任务时,会转交给浏览器的其他工作线程(上面提到的几个线程)执行,执行完之后将回调函数放入到任务队列。
在JS运行环境里,除了主线程外,还有任务队列。
// eventLoop是一个用作队列的数组
// (先进,先出)
var eventLoop = [ ];
var event;
// “永远”执行
while (true) {
// 一次tick
if (eventLoop.length > 0) {
// 拿到队列中的下一个事件
event = eventLoop.shift();
// 现在,执行下一个事件
event();
}
}
我们可以用上面的代码来想像一下JS的执行情况。 JS主线程,就像是一个while循环,会一直执行下去。在这期间,每次都会查看任务队列有没有需要执行的任务(回调函数)。在执行完一个任务之后,会继续下一个循环,直到任务队列所有任务都执行完为止。
microtask(微任务)、macrotask(宏任务)
任务队列又分微任务队列和宏任务队列
微任务
- Promise
- MutationObserver
- Object.observe()(已废弃)
宏任务
- setTimeout
- setInterval
- setImmediate
- IO
- UI rendering(DOM event)
执行过程
- 在JS执行完同步任务之后,会开始执行微任务队列
- 在将所有的微任务执行完之后,会开始执行宏任务队列
- 在执行完一个宏任务之后,跳出来,重新开始下一个循环(从1开始执行)
也就是说执行微任务队列 会将队列中的所有微任务执行完 而执行宏任务队列 每次只执行一个宏任务 然后重新开始下一个循环 我们可以看看以下代码
setTimeout(() => {
console.log(3)
new Promise((resolve, reject) => {
console.log(5)
resolve()
}).then(console.log(6))
}, 0)
setTimeout(() => {
console.log(4)
}, 0)
new Promise((resolve, reject) => {
console.log(1)
resolve()
}).then(console.log(2))
输出是1 2 3 5 6 4
我们来分析一下代码的执行过程
- 前面的两个setTimeout都是宏任务,所以现在宏任务队列有2个任务
- Promise里面的代码是同步任务,所以现在会马上执行 输出1
- Promise的then是微任务,所以现在微任务队列有1个任务
- 在执行完同步任务之后,开始执行微任务,也就是console.log(2), 输出2
- 在执行完微任务之后,会执行宏任务,第一个宏任务也就是第一个setTimeout
- 第一个setTimeout会先输出3,然后输出5,因为这两个都是同步任务,然后遇到then,加入微任务队列,宏任务执行完重新开始下一个循环。
- 因为没有同步代码,所以接着执行微任务,此时微任务队列有1个任务(第6步加入), 宏任务队列还有1个任务(第6步执行完了第一个宏任务)
- 执行微任务,输出6
- 再执行宏任务,输出4
- 2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine【强联通缩点+拓扑排序】
- 2017 Multi-University Training Contest - Team 9 1004&&HDU 6164 Dying Light【数学+模拟】
- Python3选择排序
- 【DeepMind 公开课-深度强化学习教程代码实战01】迭代法评估4*4方格世界下的随机策略
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861C Did yo
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861B Which
- 信用卡安全问题:被用户忽视的识别码
- Python3快速排序
- Python3插入排序
- Python3冒泡排序
- Python Selenium设计模式-POM
- 【Python学习笔记之一】Python关键字及其总结
- 前后端分离了,然后呢?
- 【Python学习笔记之二】浅谈Python的yield用法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux中chmod命令用法详解
- Linux强制释放占用端口以及Linux防火墙端口开放方法详解
- CentOS7.5从零安装Python3.6.6的教程详解
- 实现一台或者多台Linux实例解绑SSH密钥对
- centos7切换启动内核与切换启动模式的讲解
- Ubuntu下Sublime Text无法输入中文最简单的解决方案
- 详解linux系统输入输出管理和vim的常用功能
- 查看远程 Linux 系统中某个端口是否开启的三种方法
- Linux使用iptables限制多个IP访问你的服务器
- 在 Linux 中不使用 CD 命令进入目录/文件夹的方法
- 探索Linux内核:Kconfig的秘密
- Linux中使用命令more,less,cat查看文件内容
- SSH的ssh-keygen命令基本用法详解
- 图文详解Ubuntu搭建Ftp服务器的方法(包成功)
- Linux中chown与chmod两个命令的区别详解