在解释js事件循环机制的时候,先来看看如下几个基础知识点。
准备知识
进程 #:
操纵系统分配的占用cpu资源的最小单位.
线程 #:
官方解释,安排cpu执行的最小单位。实际就是进程内任务的细化分。
举个栗子,一个工厂,就类似于我们的cpu,那么进程就是工厂的一个车间,线程就是车间的工人。
重要一点,过个线程开启,共享统一进程的资源。
阻塞 #
非阻塞 #
js单线程
首先说,js是单线程语言,由于单线程的原因,js顺序一次只能执行一个任务。但是,这并不说明js只有一个线程。js引擎实则有多个线程,单个js脚本文件,则在一个线程运行(成为主线程),其他线程后台配合。单线程特点就是,任务循序执行,前面的执行完后面的在依次执行。执行的过程,非常简单。但是这样的执行过程,也是有弊端的。如果主线程的某一任务没?️完成,那么排在后面的任务,就会一直等待。这样的结果,导致在浏览器表现卡起(假死),不能交互。那么js真的就是这样的表现,实则不然。接下来要说的异步,解决了这一问题。
异步
javascript程序写在单个js文件,但是这个程序几乎是由多个块构成。JavaScript引擎在解析执行脚本时,是分块执行的(这里所说的块通常是函数级别的),这些块中有些是现在执行,有些则是将来执行。将来执行的,就需要一种编程方案或者说思想来解决一段时间的后的程序行为,即异步编程。
同步任务和异步任务
js程序任务分为两类,一个是同步任务,另外一类是异步任务。
同步任务,就是被js引擎添加到主线程内执行,且是顺序执行。就拿同步ajax请求为例来说,如果任务短时间没有响应,那么任务就会被一直挂起,直到返回结果(响应),才会执行下面的任务,期间是不能做任何事情的。而异步任务则不一样;还是拿上面的列,ajax发送异步请求,一旦任务开启,浏览器向服务器发起请求。浏览器发送请求到服务器响应,并返回处理结果的这段时间,js引擎不会负责,他回去处理主线程任务。直到同步任务完成,且异步任务有了响应,就会执行异步任务(回调)。
常见异步操作就是回调,其实很早我们接触了,只是没有留意。接下来,列举几个异步操作。比如超时(定时器),setTimeout,setInterval,还有异步的发起ajax,请求数据等等,不胜枚举。
结合实际:
function now() {
return 21
}; // 现在
function later() {
anwser = anwser * 2; //continuation
console.log("Mean of life:", anwser); // continuation
};
var anwser = now();//现在
//现在
setTimeout(later, 1000); // Mean of life : 42
结合案例分析代码执行顺序是,同步代码(如上标注),最优先执行,接下来在执行事件队列的continuation(异步任务)。所以说线性的代码顺序,并不能表明代码在被引擎解析执行时也是如此,从上致下的顺序。
说到异步就得说一下,js的处理各种事件执行的核心机制。。。
事件循环
#注意两点细节:
- JavaScript引擎本身任务是在“需要”时,在给定的任意时刻(这里我认为是回调调度)执行程序中代码块的;
- JavaScript引擎并不是单独运行的,还依赖他的宿主环境。常见宿主环境,比如chrome, node。
由于javascript本身没有时间概念,只是在宿主环境在需要时执行代码的环境。怎么个需要?其实这些宿主环境都有一个 共同“点”(线程)。即他们提供一种机制处理程序中的多个块的执行,且每个块执行时都会调用js引擎,这种机制就是事件循环。注意这里的事件并不能理解为,通常的鼠标,键盘等等用户同电脑交互操作的js事件。事件在这里表示(JavaScript代码的执行)。
什么是事件循环?,上面只说了他是宿主环境提供JavaScript代码运行的机制。那么这种机制具体怎么题解?如下,
事件循环队列的每一次循环称为tick。如果有等待事件,异步回调,那么就会从队列中摘下一个’事件‘执行,这些等待执行的‘事件’就是回调函数;javascript程序分为很多块,在事件循环队列严格顺序执行。严格的说,和程序不直接相关的同步事件块也会插入事件队列(任务队列?一次tick循环后的一个任务队列)
这里强调一情景,定时器本身并不会被插入事件队列,内部的回调函数也没有被挂载事件循环队列中。他所要做的就是,开启定时器。到时间后,环境会把回调函数放在事件循环队列,未来某时刻某次tick会摘下这个事件并执行。
注:
下个系列—》并发线程,并行,任务队列,任务,语句顺序。