JavaScript是单线程
JavaScript的单线程运行机制是跟它的用途有关,因为它主要应用于用户交互的过程,同一时间只能做一件事。这样才能确保用户的操作之间不会互相产生过冲突。如果是多线程的话,那么一个用户同时做了新增跟删除的操作,那么浏览器就会产生冲突,不知道该以哪个线程为准。所以,单线程是JavaScript这门语言的核心特征,将来也不会改变。
Web Worker标准
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作Dom。所以,这个新标准并没有改变JavaScript单线程的本质。
Eventloop
Eventloop主要分为主线程,宏任务和微任务。js的任务队列分为同步任务和异步任务。js所有的同步在主线程中去执行,异步任务放在宏任务(setTimeout,setInterval,setImmediate等)或者微任务(promise.then,process.nextTick)中去执行。
执行顺序
先走主线程,遇到宏任务放到宏任务执行队列,遇到微任务放到微任务执行队列。主线程执行完毕。执行微任务,微任务队列执行完毕。执行一次宏任务队列中的一个任务,执行完毕后,再去执行微任务队列。执行完毕后,一次循环
实例
setTimeout(function(){
console.log('1')
});
new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3')
});
console.log('4');
// 执行结果为 2,4,3,1
执行结果分析:因为settimeout是宏任务,虽然先执行的,但是它被放到了宏任务的执行队列里,然后代码继续往下检查看有没有微任务,检测到Promise的then函数把他放入了微任务队列。等到主线进程的所有代码执行结束后。先从微任务队列里拿回调函数,然后微任务队列全部执行完,再从宏任务队列拿函数去执行
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
// 执行结果为 1 7 6 8 2 4 3 5 9 11 10 12
执行结果分析:先去执行主线程任务,在向下执行的过程中去分出宏任务和微任务分别放到各自的执行队列中。所以第一个输出是1,向下执行碰到setTimeout放入宏任务队列,process.nextTick放入微任务队列,向下碰到new Promise,只有当执行.then回调的时候才是进入微任务队列,所以先输出 7,因为process.nextTick先进入的微任务对象,所以先输出6,再输出8。继续向下执行碰到setTimeoutt放入宏任务队列,主线程中微任务队列为空,去执行第一个宏任务setTimeout,该任务队列下继续区分宏任务,微任务。所以同理输出2 ,4 ,3 , 5。微任务队列为空,继续执行下一个宏任务。同理输出 9 ,11 ,10 ,12