前言
以前对事件循环的概念,就限于百度得到的东西。当时五花八门的解释,奇怪的自我创造词汇,仍然让现在的我云里雾里,不时的晕眩,羡慕我当时的耐性。
读了一些前端专业的书籍后,发现大多知识点都是书上有的,更详细,也更专业。
今朝再次回顾,推翻该篇笔记重写,油然觉得好的书籍重要性,也觉得好的大牛越发厉害。
一、js运行机制
1.1 js引擎
解析JavaScript代码的称之为虚拟机或者更通俗的说引擎Engine,比如Chrome浏览器和node是v8引擎,safari浏览器和Firefox浏览器也有各自的引擎。
引擎的作用是干嘛的?解析js代码,实现ECMAScript、dom、bom规范。只要能实现规范,用什么语言编写的引擎不重要,管你汇编、c、c++、java都可以。
引擎决定了js如何运行,即引擎决定了js的运行机制。
1.2 runtime
runtime即运行环境,js在浏览器中运行,则浏览器就是它的环境,在node中运行node就是它的环境。
浏览器和node环境不一样,即使是相同的解析引擎,js的行为也会不一样,。
这里主要是讲浏览器这个runtime。
二、同步和异步
2.1 概念
同步和异步是编程中的一个概念:
同步,当前线程依赖某个功能调用时,必须停下来等候其功能调用完成,得到其结果才能继续运行
异步,当前线程不依赖某个功能调用时,交给其他线程处理,自己仍然运行,不受阻碍
同步没什么好讲的,就是代码顺序执行,不受阻碍,一路执行到底。
异步的解决方案很多,比如:
- 轮询,定时轮询和长轮询,自己主动去询问
- 观察者模式,通过通知的方式告知功能调用完成
- 浏览器,详情看下面的阐述
2.2 浏览器中异步的实现
我们必须知道,在浏览器中,js是单线程,还有一件事,浏览器渲染dom的线程和js线程是互斥的,一方工作一方就停止。
所以需要时间的操作诸如定时器、ajax请求、dom渲染等等,不能立即通过js线程得到结果的,统统称之为异步,是浏览器让其它线程完成的。
- js线程遇到异步,比如ajax请求,给其注册(不注册也可以)一个函数(前端称之为回调函数,方便回来调用),类似观察者模式,不过ajax得到响应后是将回调函数放入一个队列(
任务队列
,js维护的),而不是通知js线程。 - 还有就是事件类型的,比如点击事件,也类似观察者模式,和上述情况一样。
- 不同的情况有不同的任务队列
只有js线程执行完所有你的代码后,没事干(可能你的代码还没执行完毕,这不叫没事干)之后,才会去检查各个任务队列,看队列中有没有回调函数可以执行。
其实ajax请求也能看成一个事件,可以将浏览器看作事件驱动的runtime
三、事件循环event loop
3.1概念
js线程没事干之后的情况称之为事件循环event loop:也就是js线程检查任务队列,队列中没有回调函数js线程就会一直循环检查,有回调函数就执行回调函数,这个循环过程就是event loop。
事件循环只是浏览器的实现异步的一种机制,叫什么不重要,仅仅是为了描述这一种机制而描述出来的一种概念,被广泛接受也就成为公认的了。
注意ES6中的Promise和async函数的特殊性:
promise完成后,其then或者catch或者finally中的回调函数,在promise执行完毕后相关回调函数置入promise相关的队列时,js线程优先执行(必须等手里的任务完成后)完该队列中的所有回调函数,其队列清空后,才会执行其他队列中的回调函数。
注意到这里所说的优先,当js线程执行完毕一个任务队列(非promise队列)的回调函数后,promise队列中出现了回调函数,即使该任务队列还剩余其他的回调函数,js线程也会优先处理promise队列,直到其被清空,之后又进入事件循环
async函数和promise本就有点类似,有些方面存在相同情况,有点复杂,也请自行百度
3.2总结
浏览器中的其他线程完成js线程的功能调用,完成后反馈给任务队列,这里有观察者模式的影子。
事件循环有轮询的影子。
其实各个编程很多理念都是相通的,一样的血,换个模子就让人纳闷,让人不懂
四、参考链接
问我Chrome浏览器的渲染原理
是js的加载阻塞了页面的渲染还是js的执行阻塞了页面的渲染?
【朴灵评注】JavaScript 运行机制详解:再谈Event Loop