某天,被身边小伙伴的小伙伴问了这个问题,然后我一顿胡扯,我当时自己几乎就要信了。
但是,我还是查查吧……于是有了这个总结,正文如下:
一、什么是同步、异步;什么是进程、线程?
二、为什么说JS是同步的?
三、浏览器相关
四、事件循环与消息队列
一、什么是同步、异步;什么是进程、线程?
1、同步异步:略;
2、进程:进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。
线程:线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。
参考:https://foofish.net/thread-and-process.html
二、为什么说JS是单线程的?
JS本身是一门语言,它是单线程还是多线程,由运行它的环境决定,即浏览器。因为浏览器在运行JS时,仅为JS的执行提供了一个主线程,所以JS运行时为单线程。
结论:JS的运行是单线程的。
那么,为什么浏览器只给JS分配一个线程呢?(抠搜儿)
三、浏览器
浏览器的常驻线程有如下几个:
渲染引擎线程:顾名思义,该线程负责页面的渲染
JS引擎线程:负责JS的解析和执行
定时触发器线程:处理定时事件,比如setTimeout, setInterval
事件触发线程:处理DOM事件
异步http请求线程:处理http请求
如上可见,虽然JavaScript是单线程的,可是浏览器内部不是单线程的。一些I/O操作、定时器的计时和事件监听(click, keydown...)等都是由浏览器提供的其他线程来完成的。
假设,渲染引擎已经在渲染DOM了,而JS 再次操作了DOM。或者多个线程对同一DOM做了不同处理,那么,渲染引擎到底该听谁的?一脸懵逼.jpg
所以,浏览器只为JS分配一个引擎,渲染线程和JS引擎线程是不能同时进行的。渲染线程在执行任务的时候,JS引擎线程会被挂起。
那么,问题又来了,浏览器不同线程之间,各自执行的任务结果 如何同步到JS主线程呢?--时间循环机制!
四、事件循环与消息队列
宏任务(macro-task):script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering(setTimeout/Promise等我们称之为任务源)
微任务(micro-task):process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)
消息队列:
参考:https://www.jianshu.com/p/12b9f73c5a4f
拓展:
一、同步 异步 阻塞 非阻塞
同步和异步关注的是消息通信机制;阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。