写在前面:同步任务和异步任务并不只是针对JavaScript而言,它需要有一个特殊的大环境(这里我只讨论作为js代码宿主环境之一的浏览器环境下)
首先,要想解释 消息队列和事件循环(eventloop),就要先简单聊一下浏览器编译解析代码的基本原理。
浏览器依靠进程和线程来处理每一个网页,当用户打开了一个网页(一个Tab页),此时浏览器就会开辟出一个进程来处理这个网页里面发生的所有任务。
进程的划分:
1.主进程。用来协调控制其他子进程
2.CPU进程。用于3D绘制等。
3.渲染进程。就是浏览器的内核,负责具体页面的渲染,脚本执行,事件处理等。浏览器的每个tab页都有一个渲染进程
具体进程可在浏览器的 更多工具----任务管理器 中查看:
每个进程又分为很多线程,用来处理页面中不同的数据和事件。
比如我们常说的js是一个单线程,这里的单线程通常指的是JS引擎,也就是一个tab页中用来编译和执行js代码的线程,与GUI线程互斥。
线程的划分:
除了js引擎线程。还有如下线程:
1.主线程。统一调度其他线程。
2.GUI渲染线程。负责页面渲染,布局和绘制。与JS引擎互斥。
3.事件触发线程。用来控制事件循环(鼠标点击、setTimeout、ajax等)。当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中。
4.setInterval与setTimeout所在的线程。定时任务并不是由JS引擎计时的,是由触发线程来计时的。计时完毕后,通知事件触发线程。
5.异步http请求线程。浏览器有一个单独的线程用于处理AJAX请求,当请求完成时,若有回调函数,通知事件触发线程。
6.IO线程。用来接收其他进程的消息。
好了,讲完了进程和线程的关系,就可以开始本篇文章的重点了:消息队列和事件循环
先来看一张图:
【概念解释】
消息队列:一个用来存放主线程的任务的有序集合(该队列的任务会在主线程空余时按序处理)
事件循环:任务是以事件及其回调的方式存在的。当事件(用户的点击,图片的成功加载)发生时,将其回调添加到任务队列;主线程上的任务完成之后,就会从任务队列中取出任务来执行,此过程不断重复从而形成一个循环,称为事件循环(eventLoop。)
事件循环介绍:
先声明,事件循环不属于JavaScript,在js代码中讨论事件循环是没有意义的。
在更广阔范围内的领域中的,事件循环是一个典型的 生产者消费者模型_
事件循环步骤:
1.一个tab页运行的时候,浏览器会开启一个进程用于处理该tab页。该进程有个渲染主线程用于处理很多任务(如js代码执行,页面布局计算,渲染等)
2.由于主线程一次只能执行一个任务,任务多了就需要排队来处理,这时候主线程忙不过来,便将自己的任务依次列在了一个待办任务清单里面,这个待办任务清单就是消息队列
3.当主线程手头上的任务完成以后,就会抽取消息队列的任务来完成,此过程不断重复就会形成一个循环,称为eventLoop。
最后贴上大佬的博客:
JavaScript 运行机制详解:再谈Event Loop - 阮一峰的网络日志https://www.ruanyifeng.com/blog/2014/10/event-loop.html