先执行执行栈中的同步任务
异步任务(回调函数)放入任务队列中
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获得任务,执行任务,再获取任务,再执行,所以这种机制被称为“事件循环”(event loop)
1、javsscript语言是单线程?
javsscript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事,这是因为 javascript 这门脚本语言诞生的使命所致--javascript 是为处理页面中用户的交互,以及操作DOM而诞生的,比如我们对某个DOM 元素进行添加和删除操作,不能同时进行,应该先进行添加,之后再删除
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务,这样所导致的问题是:如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
同步和异步
为了解决这个问题,利用多核CPU的计算能力,HTML5提出Web Worker 标准,允许JavaScript脚本创建多个线程,于是,js中出现了同步和异步。
同步:前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。
异步:你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。
它们的本质区别:这条流水线上各个流程的执行顺序不同
同步任务:同步任务都在主线程上执行,形成一个执行栈
异步任务:js 的异步任务事通过回调函数实现的。一般而言,异步任务有以下三种类型:
①普通事件:如 click , resize等
②资源加载:如 load , error 等
③定时器:包括 setInterval , setTimeout等
异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)
2、js异步任务的类型?
①、普通事件:如 click , resize等
②、资源加载:如 load , error 等
③、定时器:包括 setInterval , setTimeout等
进程与线程
什么是进程
我们都知道,CPU
是计算机的核心,承担所有的计算任务
官网说法,进程
是CPU
资源分配的最小单位
字面意思就是进行中的程序,我将它理解为一个可以独立运行且拥有自己的资源空间的任务程序
进程
包括运行中的程序和程序所使用到的内存和系统资源
CPU可以有很多进程,我们的电脑每打开一个软件就会产生一个或多个
进程,为什么电脑运行的软件多就会卡,是因为
CPU给每个
进程分配资源空间,但是一个
CPU一共就那么多资源,分出去越多,越卡,每个
进程之间是相互独立的,
CPU在运行一个
进程时,其他的进程处于非运行状态,
CPU使用 [时间片轮转调度算法](https://link.juejin.cn?target=undefined) 来实现同时运行多个
进程
什么是线程
线程
是CPU
调度的最小单位
线程是建立在
进程的基础上的一次程序运行单位,通俗点解释
线程就是程序中的一个执行流,一个
进程可以有多个
线程
一个进程
中只有一个执行流称作单线程
,即程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行
一个进程
中有多个执行流称作多线程
,即在一个程序中可以同时运行多个不同的线程
来执行不同的任务, 也就是说允许单个程序创建多个并行执行的线程
来完成各自的任务
进程和线程的区别
进程是操作系统分配资源的最小单位,线程是程序执行的最小单位
一个进程由一个或多个线程组成,线程可以理解为是一个进程中代码的不同执行路线
进程之间相互独立,但同一进程下的各个线程间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号)
调度和切换:线程上下文切换比进程上下文切换要快得多
JS为什么是单线程
JS的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
还有人说js还有Worker线程,对的,为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程是完 全受主线程控制的,而且不得操作DOM
所以,这个标准并没有改变JavaScript是单线程的本质
宏任务(macrotask) & 微任务(microtask)
宏任务(macrotask)
在ECMAScript中,macrotask
也被称为task
我们可以将每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行), 每一个宏任务会从头到尾执行完毕,不会执行其他
由于JS引擎线程
和GUI渲染线程
是互斥的关系,浏览器为了能够使宏任务
和DOM任务
有序的进行,会在一个宏任务
执行结果后,在下一个宏任务
执行前,GUI渲染线程
开始工作,对页面进行渲染
宏任务 -> GUI渲染 -> 宏任务 -> ...
常见的宏任务
- 主代码块
- setTimeout
- setInterval
- setImmediate ()-Node
- requestAnimationFrame ()-浏览器
微任务(microtask)
ES6新引入了Promise标准,同时浏览器实现上多了一个microtask
微任务概念,在ECMAScript中,microtask
也被称为jobs
我们已经知道宏任务
结束后,会执行渲染,然后执行下一个宏任务
, 而微任务可以理解成在当前宏任务
执行后立即执行的任务
当一个宏任务
执行完,会在渲染前,将执行期间所产生的所有微任务
都执行完
宏任务 -> 微任务 -> GUI渲染 -> 宏任务 -> ...
常见微任务
- process.nextTick ()-Node
- Promise.then()
- catch
- finally
- Object.observe
- MutationObserver
堆和栈的概念和区别
栈内存:
栈内存主要用来执行程序用的,存储的是局部变量和对象的引用,凡是定义在方法中的都是局部变量,for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,一旦离开作用域,变量就会被释放。栈内存更新的速度很快,因为局部变量的生命周期很短。
栈内存可以类似看做是一个矿泉水瓶,往里面放入东西,会马上沉入底部,所以它的特点是:
先进后出,后进先出
栈的存储速度比堆要快,仅次于寄存器,栈数据是可以共享,但是缺点是,存在栈中的数据大小和生存必须是确定的,缺乏灵活性
栈内存可以称为一级缓存,由垃圾回收器自动回收。
堆内存:
堆内存存储的是数组和对象(数组是特殊的对象),凡是new建立的都在堆里,堆中存放都是对象,对象用于封装数据,而且是封装多个属性,如果一个属性消失,这个实体也不会消失,还可以用,所以堆不会随时释放的。虽然对象不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的回收。
堆其实可以类似看做是管道,或者说是平时去排队买票,特点是:先进先出,后进后出
堆是在运行时动态分配内存的,存储速度较慢
堆内存可以称为二级缓存,堆中的对象不会随时释放,一般需要开发人员自己回收它
堆和栈的区别:
1. 栈内存存储的是局部变量,而堆内存存储的是实体对象。
2. 栈的更新速度要快于堆内存,因为局部变量的生命周期很短。 V栈 > V堆
3. 栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
4. 共享性不同,栈内存是线程私有的,堆内存是所有线程共有的。
5. 栈使用一级缓存,通常是被调用时处于存储空间,调用完立即释放。
堆存放在二级缓存中,生命周期由虚拟机的垃圾回收算法决定。
6. 堆是先进先出,后进后出,栈是先进后出,后进先出
7. 栈的空间远远小于堆的空间