js的异步运行逻辑

js代码在浏览器当中的异步执行主要是依靠Call stack(调用栈)、Event loop(事件循环)、Queue(消息队列)这三个模块来完成的。


image.png

1、首先加载整体代码,在调用栈Call stack中压入一个全局的匿名函数调用,然后依次执行每行代码。


image.png

2、同步代码按顺序执行,先压栈,然后执行,然后打印,打印完之后弹出执行栈。


image.png

3、异步调用也是先压入调用栈,但是这里延时器内部函数是异步的,所以这里需要关心内部函数到底做了什么。


image.png

4、延时器为timer1函数开启了一个时长为1.8s的倒计时器,延时器是单独工作的,并不会受到js线程的影响,在延时器调用时,倒计时就已经开始了。并且延时器的调用就已经完成了,因此代码会向下继续执行。


image.png

5、下面又是开启延时器,流程和上面一样,都是先压栈,然后开启延时器,然后弹出执行栈。
image.png

6、最后一个console.log的调用和第一行相同,打印完之后,调用栈中匿名调用就结束了,这个时候调用栈就会被清空掉。


image.png

7、这个时候调用栈里已经没有工作了,事件循环(Event Loop)就开始工作了。Event Loop的作用就是监听调用栈(Call stack)和消息队列(Queue)。一旦调用栈中的任务都结束了,事件循环就会从消息队列中取出第一个回调函数压入调用栈中去执行。如果消息队列中为空,则暂停执行。
8、这个时候我们回过头来看之前调用的倒计时器,timer2对应的延时时间是1s小于timer1的1.8s,因此timer2的延时会先结束,并且率先进入消息队列中等待执行。
image.png

image.png

image.png

9、而此时事件循环将能够监听到消息队列发生了变化,则将按执行顺序将timer2先压入执行栈中去执行,执行过程和之前的执行过程是一致的。
image.png

10、而如果遇到层层套娃,异步里面又嵌套了异步也是一样的道理,将异步函数先放到异步API当中去执行,等待本轮执行再按照上面的逻辑去执行。直到调用栈和消息队列中都没有需要执行的任务了,整体的代码执行就结束了。


image.png

总结:
1、如果是调用栈是一个正在执行的工作表,消息队列就可以理解为一个待办的工作表。
2、js执行引擎会先执行完当前调用栈当中的任务,然后通过事件循环,从待办的工作表(消息队列)里再取一个任务出来执行,循环往复。
3、这个过程中我们随时都可以继续往消息队列中再放入新的任务,消息队列会排队等待事件循环。

以上就是异步调用在js当中的实现过程,以及基本的原理,整个过程都是通过消息队列和异步循环来处理的。


image.png

js是单线程的,但是浏览器并不是单线程的。具体来讲就是通过js调用的很多api并非单线程的,例如延时器等,它内部会有一个单独的线程负责去执行,在指定的时间后将内部的回调函数放入消息队列。我们所说的单线程,是执行我们代码的线程是单线程,而这些异步的api会有他们自己的线程去执行他们的一些操作,而此时,js的执行线程并不会去等待他们执行完再执行下面的代码。

同步异步并不是我们写代码的方式,而是我们使用的api是以同步方式还是异步方式来工作的。
所谓同步就是阻塞,当前代码执行完,下面的代码才会执行。
所谓的异步就是非阻塞,先在待执行任务列表中等待同步代码执行完,再回来执行,并且异步代码的执行并不会阻塞下面的代码。

你可能感兴趣的:(js的异步运行逻辑)