JS由于操作DOM和用户交互的用途,是单线程模型的,也就是一次只能执行一个事件,这样避免混乱的执行机制,比如添加元素的同时又删除它引起矛盾。而单线程意味着事件和任务需要排队进行,这就是队列(queue),队列是“先进先出”的执行顺序,js把一些任务“挂起”,等待前面的任务执行完再回来执行“挂起”任务,所以任务分为同步任务(synchronous)和异步任务(asynchronous),同步任务指的是在主线程上执行的任务,执行完一个执行下一个,异步任务则是在任务队列中的某个异步线程。当主线程的堆栈为空时将任务队列的event推入堆栈中,处理其它消息前会先处理当前事件回调。
而对于任务队列,它分为宏任务(macrotasks)和微任务(microtasks),宏任务包含setTimeout,setInterval,setImmediate,UI rendering等,微任务包括promise(原生),process.nextTick,observe等,整体的script代码同步执行完就执行microtasks,然后再执行macrotasks,如此反复循环。
接下来看一段代码
var pro=new Promise((res,rej)=>{
console.log('promise_1');
res();
}).then(()=>{
console.log('promise_2');
})
console.log('start')
const interval = setInterval(() => {
console.log('setInterval')
}, 0)
setTimeout(() => {
console.log('setTimeout 1')
Promise.resolve()
.then(() => {
console.log('promise 3')
})
.then(() => {
console.log('promise 4')
})
.then(() => {
setTimeout(() => {
console.log('setTimeout 2')
Promise.resolve()
.then(() => {
console.log('promise 5')
})
.then(() => {
console.log('promise 6')
})
.then(() => {
clearInterval(interval)
})
}, 0)
})
}, 0)
Promise.resolve()
.then(() => {
console.log('promise 1')
})
.then(() => {
console.log('promise 2')
})
分析一下,首先执行同步任务,输出promise_1和start,此时执行任务队列中第一个任务,输出promise_2,然后先执行微任务Promise,输出promise 1和promise 2,然后是任务队列中的interval定时器,然后是setTimeout定时器,此时interval定时器又进入任务队列中,又一次输出setInterval,再执行then里的定时器,最后清除interval定时器便不再输出setInterval
所以结果如下:
(纯个人理解,如有差错,一起探讨)