依然是:经济基础决定上层建筑。javascript
先解释现代js引擎几个概念。html
为了方便描述与理解,做出如下约定:html5
js 是一门单线程语言。 js 引擎有一个主线程(main thread)用来解释和执行 js 程序,实际上还存在其余的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在node.js中)等等。这些线程可能存在于 js 引擎以内,也可能存在于 js 引擎以外,在此咱们不作区分。不妨叫它们工做线程。可是前辈们很有一种小本本记好的说法,那就是,要相信 js 单线程的本质,其余一切看似多线程,都是纸老虎。哈哈哈哈哈哈哈哈哈哈哈哈哈......java
任务分为同步任务(synchronous)和异步任务(asynchronous),若是全部任务都由主线程来处理,会出现主线程被阻塞而使得页面“假死”。为了主线程不被阻塞,异步任务(如:AJAX异步请求,定时器等)就会交给工做线程来处理,异步任务完成后将异步回调函数注册进任务队列,等待主线程空闲时调用。流程如图:node
// example console.log('example-start') setTimeout(() => { console.log('setTimeout-0') }, 0) console.log('example-end') /* chrome result * example-start example-end setTimeout-0 * */
上面一个简单的小 js 片断的执行过程:git
最后借用Philip Roberts的生动形象的一张图,callback queue能够简单理解为任务队列,详细的下面会讲。github
然而Event Loop并无上面图中描述那么简单。心塞塞 : (web
根据规范,事件循环是经过任务队列的机制来进行协调的。一个 Event Loop 中,能够有一个或者多个任务队列(task queue),一个任务队列即是一系列有序任务(task)的集合;每一个任务都有一个任务源(task source),源自同一个任务源的 task 必须放到同一个任务队列,从不一样源来的则被添加到不一样队列。chrome
setTimeout/Promise 等API即是任务源,而进入任务队列的是他们指定的具体执行任务(回调函数)。来自不一样任务源的任务会进入到不一样的任务队列。其中setTimeout与setInterval是同源的。vim
仔细查阅规范可知,异步任务可分为 task(部分文章也称为 macro-task) 和 micro-task 两类,不一样的API注册的异步任务会依次进入自身对应的队列中,而后等待 Event Loop 将它们依次压入执行栈中执行。
在事件循环中,每进行一次循环操做称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤以下:
一个事件循环(Event Loop)中,主线程从任务队列中取出一个任务 task 执行时,而这个正在执行的任务就是从 task queue(部分文章也称为 macro-task queue)中来的。当这个 task 执行结束后,js 会将 micro-task queue中全部 micro-task 都在同一个 Event Loop 中执行,当这些 micro-task 执行结束后还能继续添加 micro-task 一直到整个 micro-task 队列执行结束。而后当前本轮的 Event Loop 结束,主线程能够继续取下一个 task 执行。因此更详细的 Event Loop 的流程图以下:
// example console.log('example-start') setTimeout(() => { console.log('setTimeout-0') // setTimeout-1 }, 0) new Promise((resolve, reject) => { console.log('promise-1') resolve('promise-2') Promise.resolve().then(() => console.log('promise-3')) // then-1 }).then((response) => { // then-2 console.log(response) setTimeout(() => { console.log('setTimeout-10') // setTimeout-2 }, 10) }) console.log('example-end') /* chrome result * example-start promise-1 example-end promise-3 promise-2 setTimeout-0 setTimeout-10 * */
上面一个简单的 js 片断的执行过程:
若是上文理解有误或者有疑惑,欢迎交流。
好记性不如烂笔头。