javascript是单线程语言,也就是说代码只能一个接一个地被顺序处理。可奇怪的是既然是单线程,那它是怎么做到异步呢?
我们就来一起研究一下,javascript的运行机制和异步的实现
console.log(1);
setTimeout(()=>{
console.log(2);
new Promise((resolve)=>{
console.log(3);
resolve()
}).then(()=>{
console.log(4)
})
})
new Promise((resolve)=>{
console.log(5);
resolve()
}).then(()=>{
console.log(6)
})
setTimeout(()=>{
console.log(7)
})
我们一起来看一下这段代码的执行结果。(由于浏览器和node环境的运行略有不同,这里按浏览器输出为准)
1
5
6
2
3
4
7
在分析为什么会得出这个结果前,我们需要先了解几个概念
1.宏任务和微任务
而宏任务一般是:包括整体代码script,setTimeout,setInterval、setImmediate。
微任务:原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、 MutationObserver 。
2.事件队列
队列是一种数据结构,主要特征就是先进先出,例如一个只能在最后添加数据,在头部取数据的数组。事件队列是存放宏任务事件的队列。
3.事件表
执行代码过程中,遇到异步事件,会把回调事件注册在事件表中,到需要执行回调事件时,将事件表中的回调事件移入事件队列中
4.微任务事件队列(MicroTask)
存放微任务事件的队列
然后分析一下一开始的题目
1.执行console.log(1);----------------->输出1
2.将setTimeout的回调注册到事件表中,因为没有设置时间,所以移入事件队列中;
3.执行promise;--------------------->输出5,将回调移入微任务队列中
4.将setTimeout的回调注册到事件表中,因为没有设置时间,所以移入事件队列中;
5.第一轮执行完成
6.执行微任务队列中的所有任务----------->输出6
7.在事件队列中移出事件执行------------->执行第一个setTimeout的回调事件
8.执行console.log(2);------------------>输出2
9.执行promise;--------------------->输出3,将回调移入微任务队列中
10.第二轮执行完成
11.执行微任务队列中的所有任务----------->输出4
12.在事件队列中移出事件执行------------->执行第二个setTimeout的回调事件
13.执行console.log(7)------------------->输出7
所以结果为
1562347
还有需要注意的是,每当执行完一次宏任务,都会将微任务队列中的全部任务执行,执行后再执行下一个宏任务。所以promise.then要比setTimeout要先执行