为什么js是单线程的
我们用反证法证明这个问题,假设js是多线程的。
场景描述:
假设现在有2个进程:process1,process2。由于是js是多进程的,所以这两个进程同时对一个dom进行操作。
process1 删除了该dom。
process2 编辑了该dom。
同时下达2个矛盾的命令,浏览器究竟该如何执行呢?
显然作为浏览器脚本语言,就决定了js只能是单线程的,也称为主线程。
JS为什么需要异步
同样用反证法,假设js是同步的。
场景描述:
如果JS中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。
对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验。
JS单线程又是如何实现异步的呢?
通过的事件循环(event loop)实现异步。
什么是事件循环
js任务分类:
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval
- micro-task(微任务):Promise.then(),MutationObserver。
event loop:
- 执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
- 当前宏任务执行完成后,会查看微任务的【事件队列】
- 如果有微任务,将里面全部的微任务依次执行完
- 如果没有微任务,跳到第1步。
event loop图解
总结:
涉及概念: 运行栈(同步任务)、任务队列(异步任务)、event loop
不断去任务队列中取异步任务的过程叫event loop
什么时候会开启异步任务:setTimeout 和 setIntveral、DOM事件、es6中的promise等
语句放入异步任务队列时机:遇到异步任务不会立刻把代码放到任务队列中,会等到触发时(settimeout 时间到了 dom事件触发了)在放到任务队列中:
var a= 1;
setTimeout(a, 1000);
setTimeout(b, 500);
//b先被放到异步队列
例子
例子1
// 1 3 2
console.log(1); //同步任务
setTimeout(function(){ //异步任务
console.log(2);
},0)
console.log(3); //同步任务
例子2
// 1
console.log(1); //同步任务
while(true){ //同步任务
}
console.log(2); //同步任务
例子3
// 1
console.log(1); //同步任务
setTimeout(function(){ //异步任务
console.log(2);
},0)
while(true){ //同步任务
}
例子4
//4 4 4 4
for(var i=0;i<4;i++){ //同步任务
setTimeout(function(){ //异步任务
console.log(i);
},1000)
}
例子5
//2 4 3 1
setTimeout(function(){
console.log('1')
});
new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3')
});
console.log('4');