1.什么是事件循环
主线程不断从消息队列中获取消息,执行消息,这个过程成为事件循环,这种机制叫做循环机制,取一次消息并执行的过程叫一次循环。
2.宏任务和微任务
宏任务:可以理解每次执行栈执行的任务就是一个宏任务,这其中也包含每次从任务队列中获取一个事件回调并放入执行栈中执行。浏览器在每执行完一个宏任务之后,下一个宏任务开始执行之前,对页面进行重新的渲染。
微任务:可以理解为在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前微任务会被执行。在某一个宏任务执行完后,就会将在它执行期间产生的所有微任务都执行完毕(在渲染前)。
3.事件循环运行机制
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务执行过程基本是这样的:
- 执行一个宏任务,如果执行栈中没有就从任务队列中获取
- 执行过程中如果产生微任务,就加他添加到微任务队列中
- 宏任务执行完毕之后,立即依次执行微任务队列中的所有微任务
- 当前宏任务执行完毕之后,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕之后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
eg:
for (var i = 1; i <= 10; i++) { setTimeout(function () { console.log(i); }, 1000); } //结果打印了10个11
- for 循环是一个同步任务,在主线程上执行,形成一个执行栈,i从1-10,依次遍历
- i从1-10,依次遍历过程中,都会遇到
setTimeout
,则浏览器渲染进程新开一个定时器触发线程,这时,for循环所在的线程和定时器所在的线程并发执行 setTimeout
里面的回调函数是一个异步操作,事件循环线程会把它加入到任务源为setTimeout
的任务队列中,并没有执行- for循环中当i=11时,退出for循环,该同步任务结束,此时,主线程的执行栈中没有其他的同步任务了,于是开始依次从任务源为
setTimeout
的任务队列中读取任务(回调函数)并加入到主线程执行栈中执行,因此,打印了10个11