在学习eventloop以前,咱们须要复习一下js的单线程和异步。
虽然说js是单线程的,可是在浏览器和Node中都作了相应的处理。如浏览器中的web workers(工做线程),Node中的child_process(子进程)。它们的出现对大量计算的分解起到了促进做用。
当进程启动时,Node会建立一个tick循环,每一个tick循环经过内部的观察者来查看是否有事件须要处理,若是有就取出事件和它相关的回调函数去执行,执行完之后就进入下一个循环,若是再也不有就退出进程。html
在浏览器中把异步事件放到工做线程中,避免阻塞主线程UI的渲染
console.log('进程开始') const ajax = new XMLHttpRequest() ajax.addEventListener('load', () => { console.log('load') }) ajax.addEventListener('loadend', () => { if (ajax.readyState == 4 && ajax.status == 200) { console.log('ajax success') } else { console.log('ajax success') } }) ajax.open('get', 'http://localhost/study/html/vue.js') ajax.send() setTimeout(() => { console.log('setTimeout') }, 300) fetch('http://localhost/study/html/demo.json',{ headers: { 'content-type': 'application/json' } }).then(res => { console.log('fetch') }) let i = 0 while(i < 10000) { i++ } console.log(i) console.log('进程结束')
从结果能够看出三种异步处理不阻塞主线程代码的执行,而ajax、fetch、setTimeout根据代码处理结束的前后来执行回调函数。
Node中的事件循环根据观察者的优先级来执行,同一个循环内的process.nextTick -> setTimeout -> setImmediate
setTimeout(() => { console.log('setTimeout') }, 0) setImmediate(() => { console.log('setImmediate1') process.nextTick(() => { console.log('setImmediate1 插入nextTick') }) }) setImmediate(() => { console.log('setImmediate2') }) process.nextTick(() => { setTimeout(() => { console.log('nextTick1 setTimeout') }, 100) console.log('nextTick1') }) process.nextTick(() => { console.log('nextTick2') }) console.log('正常执行')
事件循环的执行特色,源于利用单线程,远离多线程死锁、状态同步等问题;利用异步让单线程远离阻塞,以更好的使用CPU。