JS是一门单线程的语言,这意味着同一时间内只能做一件事,但是这并不代表单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环。具体过程为:
- 当JS执行代码时,通过将不同函数的执行上下文压入执行上下文栈中来保证代码的有序执行。
- 在执行同步代码时,如果遇到异步事件,JS引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行上下文栈中的其他任务。
- 当同步事件执行完毕后,再将异步事件对应的回调函数加入到一个任务队列中等待执行。任务队列可以分为宏任务队列和微任务队列,当当前执行上下文栈中的事件执行完毕后,JS引擎首先会判断微任务队列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行;当微任务队列中的任务都执行完成后再去执行宏任务队列中的任务。
执行过程:
- 执行一个宏任务,如果遇到微任务就将它放到微任务的队列中。
- 当前宏任务执行完成后,会查看微任务的队列,然后将里面的所有微任务依次执行完。
eg:
console.log(1); setTimeout(()=>{ console.log(2); }, 0); new Promise((resolve, reject)=>{ console.log('new Promise'); resolve() }).then(()=>{ console.log('then'); }) console.log(3);执行步骤:
- console.log(1),同步任务,主线程直接执行,直接打印1。
- setTimeout(),属于异步任务中的新的宏任务,留着后面执行。
- new Promise,同步任务,主线程直接执行,直接打印new Promise。
- .then,属于异步任务中的新的微任务,留着后面执行。
- console.log(3),同步任务,主线程直接执行 ,直接打印3。
结果是:1=>new Promise=>3=>then=>2
// 第一次宏任务执行完毕后去微任务队列查看是否有微任务,发现.then的回调,打印then。
// 再去执行新的宏任务,这里就剩一个定时器的宏任务了,打印2。