一、进程和线程
- 进程是 cpu 资源分配的最小单位(是能拥有资源和独立运行的最小单位)
- 线程是 cpu 调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)
讲真,不准备的话我是真说不出一些高大上的术语来o(╥﹏╥)o。
通俗理解的话可以把cpu当做一个工厂,?当做电力,工厂时刻运行着,?有限,只能给一个车间使用,工厂通电给车间运行时,就相当于开启了一个进程。浏览器新开一个tab页时就会新建一个进程,可以通过任务管理器来查看到。
车间运行需要工人,工人相当于线程可以拥有多个,车间的空间是工人共享的,每个线程都可以使用这些共享内存,但是空间内的房间大小不同容纳的人数也不同,房间人满后其他人想进来只能等某个人出去,还有一些房间只能容纳一个人使用,例如卫生间,陷进去人会把门锁上,防止其他人进来,后到的人只能在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
二、浏览器
浏览器解析html构建dom树,解析css构建渲染树,构建完成后绘制到屏幕上(这里还涉及到reflow(回流)和repain(重绘)两个概念)。
JS的解析是由浏览器中的JS解析引擎完成的,JS是单线程运行,同一个时间内只能做一件事,所有的任务都需要排队有序进行(如果是多线程话一个增加一个删除这样)。如果遇到某个任务耗时过长,其他任务只能等待。所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)
三、主线程、任务队列、事件循环
JS的执行机制就可以看做是一个主线程加上一个任务队列(taskqueue),同步任务放在主线程上执行的任务形成一个执行栈(execution context stack),异步任务是放在任务队列中的任务。主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列"进入执行栈,开始执行。主线程循环不断的从"任务队列"中读取事件(Event Loop事件循环)
四、宏任务和微任务
读取任务队列时会优先执行宏任务(setTimeout,setInterval),微任务(Promise,process.nextTick),当前任务队列执行完毕后主线程会循环下一个任务队列进入执行。
console.log(1)
setTimeout(()=>{
console.log(2)
},0)
console.log(3)
new Promise((resolve,reject) => {
console.log(4);
resolve(5)
console.log(6)
})
五、区别
setTimeout(fn, 0) 并非真的是立即执行,而是要等待至少 4ms (事实上可能是 10ms)才会执行这意味着如果没有微任务的概念,我们仍然采用宏任务的机制去执行 async function(实际上就是 Promise) ,性能会非常的糟糕。而且对于正在执行一些复杂任务的页面(例如绘制)就更加糟糕了,整个循环都会被这个任务直接阻塞。微任务就是为了适应这种场景,和宏任务最大的不同在于,如果在执行微任务的过程中我们往任务队列中新增了任务,浏览器会全部消费掉为止,再进入下一个循环。这也是为什么微任务和宏任务的时序上会存在差别。
作者:方凳雅集 链接:juejin.cn/post/685457… 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。