搞懂js运行机制,明确代码的输出内容和顺序
js是一门单线程语言
Event Loop 是js的执行机制
每个时间点,系统只会处理一个事件
js是单线程语言,按照语句出现的顺序执行的。所有异步,都是用同步的方法去模拟实现
1.进程和线程:
计算机的核心是CPU,承担所有的计算任务
单个cpu一次只能运行一个任务:cpu像一个工厂,即单个工厂开工
CPU总是运行一个进程,其他进程处于非运行状态:进程好比工厂的车间,是所能处理的单个任务
一个进程可以包括多个线程:一个车间有很多工人,协同完成一个任务,线程好比车间的工人
一个进程的内存空间是共享的,每个线程都可以使用这些共享内存,车间的空间是工人共享的,许多的房间是每个工人都可以进出的
一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这块的内存
防止多个线程同时读写某一块内存区域,防止另外进入,加上互斥锁(Mutual),排队等待再进去,
某些内存区域,只能供给固定数目的线程使用,多出来的需要排队等候信号量(Semaphore),保证多个线程不会互相冲突
2.macrotask(宏任务) 和 microtask(微任务)
Macrotasks包含生成dom对象、解析HTML、执行主线程js代码、更改当前URL还有其他的一些事件如页面加载、输入、网络事件和定时器事件。
macrotask代表一些离散的独立的工作。当执行完一个task后,浏览器可以继续其他的工作如页面重渲染和垃圾回收。
Microtasks则是完成一些更新应用程序状态的较小任务,如处理promise的回调和DOM的修改,这些任务在浏览器重渲染前执行。Microtask应该以异步的方式尽快执行,其开销比执行一个新的macrotask要小。Microtasks使得我们可以在UI重渲染之前执行某些任务,从而避免了不必要的UI渲染,这些渲染可能导致显示的应用程序状态不一致。
3.事件循环:
Event loop 是JS采用机制,用来解决单线程运行造成的一些问题
一般情况下一个进程一次只能执行一个任务
如果有多任务需要执行,不外乎三种解决方法:
1.排队
2.新建进程,使用fork命令,为每个任务新建一个进程
3.新建线程,因为进程耗费资源,多一个进程包含多个线程,由线程去完成任务
js是单线程执行,Event loop的提出:
简单说就是程序中设置两个线程:
一个是负责程序本身的运行,成为’主线程‘,
另一个是负责主线程与其他线程的通信(EVENT loop)的消息线程,不断重复执行
用户自定义的回调函数,通常在浏览器的默认动作之前触发
js按照语句出现的顺序执行
js同步及异步得执行过程:
事件循环:
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册回调函数。
经过指定时间当指定的事情完成时,任务队列Event Table会将这个函数移入Event Queue回调函数队列。
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,检查是否有等待被调用的函数,如果有则进入主线程执行。
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
调用执行栈:所有代码都会被放到执行栈中执行。后进先出,调用栈内存放的是代码执行期间的所有执行上下文。
执行机制:
任务队列
2.setTimeout
setTimeout(fn,0)指定某个任务在主线程最早可得得空闲时间执行,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行
3.setInterval
setInterval(fn,ms)循环的执行,会每隔指定的时间将注册的函数置入Event queue,如果前面的任务号是太久,同样需要等待。不是每过ms秒会执行一次fn,而是每过ms秒,会有fn进入Event Queue
4.Promise 与process.nextTick(callback)
process.nextTick:在事件循环的下一次循环中调用callback
Promise,new Promiss直接执行,then函数发布到微任务Event Queue
立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务
promise中的代码是被当作同步任务立即执行的
在async/await中,await出现之前及本身,其中的代码也是立即执行的
await之后的代码是微任务,会放入到任务队列
左右等价
不同类型的任务会进入对应的Event Queue
除了广义的同步任务和异步任务,对任务更精细的定义:
宏任务和微任务:
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval
- micro-task(微任务):Promise.then,process.nextTick
事件循环,宏任务,微任务的关系如下图:
事件循环时,一轮循环结束,会执行所有微任务
事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从一个宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务
例1: