【知识点】JS运行机制

214 阅读2分钟

为什么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. 执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
  2. 当前宏任务执行完成后,会查看微任务的【事件队列】
  3. 如果有微任务,将里面全部的微任务依次执行完
  4. 如果没有微任务,跳到第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');