先出一道题:
console.log('a'); setTimeout(function (){ console.log('b'); },1000); console.log('c');
如果你给出的结果是:a c b,且明白为什么,此篇文章可以跳过。
--------------------------------------------------------分割线-------------------------------------------------------------
首先我们要记住JavaScript是单线程,setTimeout没有实现多线程,但是浏览器是多线程的。
JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序。
浏览器的内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器至少实现三个常驻线程:JavaScript引擎线程,GUI渲染线程,浏览器事件触发线程。
*JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JavaScript线程在运行JavaScript程序。
*GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。但需要注意,GUI渲染线程与JavaScript引擎是互斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI
更新会被保存在一个队列中等到 JavaScript引擎空闲时立即被执行。
*事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JavaScript引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeout、也可来自浏览器内核的其他线程如鼠标点击、Ajax
异步请求等,但由于JavaScript的单线程关系所有这些事件都得排队等待JavaScript引擎处理(当线程中没有执行任何同步代码的前提下才会执行异步代码)。
JavaScript脚本内容分为两种类型:同步任务(脚本主线程任务)和异步任务(ajax、setTimeout、等等)。
一个window打开后,浏览器就创建如上3个线程(还有其他),解析玩html构建dom树后,JavaScript解析器开始解析js文件,开始按序执行脚本,一旦发现一个异步事件,比如一个setTimeout 3000,然后将此异步任务丢入事件触发线程后,然后就继续执行后边的代码,而这个异步任务当完成等待3s后就会被坊间事件队列,如果主线程的同步任务执行完后,就会从Event queue里边逐条取出,然后执行。
参考:https://www.cnblogs.com/giggle/p/5346531.html
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://blog.csdn.net/zhaoxiaozhao622/article/details/78140672