试着讲清楚:js代码运行机制

js运行机制

经常看文章的说到js是单线程的,其实这个说法非常的模糊和误导性,准确的是js执行引擎是单线程的(js运行环境不止js引擎),js执行引擎就是js代码的执行器,有了这些概念就可以下来说说js是如何运行的了。

3种特殊的js代码类型

在js代码执行的时候,js的代码是按照顺序执行的,从上到下,这个时候是同步执行的,不过,有几个例外,先记下来:

  • 异步的网络请求
  • 事件绑定、事件监听器
  • 时间触发函数

3种代码特殊在哪?

我们模拟一下,js引擎遇到这三类代码的情况:

  1. js代码被执行好好的,正在顺序执行代码,这个时候呢,遇到了异步的网络请求的代码,调用了之后没有等待网络结果,就继续执行之后的js代码了,这与js代码执行是单线程的不符合(不考虑h5),那么肯定异步网络请求调用之后,不是js执行引擎管理了。
    问题一:谁在等待,谁之后通知js执行引擎结果,毕竟是js代码就得js引擎是执行。

  2. 有了第一个问题,我们已经知道肯定有除了js执行引擎之外的模块参与了上面的事情了,先放着不讨论,之后js代码继续执行着,然后遇到了事件绑定和事件监听函数,哦,这个js调用之后,也是继续往下走的,并没有调用那些函数内容,这与js代码执行是单线程的不符合(不考虑h5),我们知道,事件函数只有在事件触发的时候会起作用。那么问题来了:
    问题二:谁把事件关联的函数保存的,以便接收事件触发选择正确的事件处理函数,通知js执行引擎?

  3. js代码在遇到setTimeout和setInternal函数的时候,也是不直接执行,毕竟里面的代码也没有立刻执行,那么问题产生了如下问题:
    问题三:谁在监视时间流逝选择合适的触发函数通知js引擎执行的?

以上3点是在自己学习js的运行机制和js执行引擎的时候,遇到了3个问题,那么3个问题其中的js执行js代码,但是监视肯定不是js执行引擎,答案如下:

  1. 异步网络请求线程
  2. 事件触发线程
  3. 定时触发器线程

以上3个线程是独立于js执行引擎之外,帮助处理这3类代码的,所以啊,千万不要认为js引擎什么都做,加上gui渲染线程,js执行引擎线程,5个线程齐了。

3种代码如何执行?

以上我们了解了js执行的代码和3个额外的线程协助下,js执行代码构建了完备的环境了,但是js执行引擎是如何执行这3类线程给的函数的?毕竟js代码都是在js执行引擎里面执行的:
答案是队列(暂且叫做Message Queue)

3个线程根据功能职责,会把要执行的代码封装成一个结构(消息),放到队列里面,js执行完同步代码之后,才会循环的在这个队列里面取结构(消息),取到了,那么就执行,取不到了就等待。

从以上的一个执行逻辑,那么我们就可以得出一个结论:
js在遇到这3类代码的时候,一定滞后于同步代码的
因为同步代码执行完成之后,js执行引擎才会从队列中取一条结构(消息)去执行,并且执行完成之后才会再取下一条。

以上也就是为什么我们经常看到时间处理函数总是在同步代码之后执行的原因、异步网络请求的回调函数也在同步代码执行完成之后调用的原理;就是因为这3类函数被3类线程放到了队列里了,而队列里面的代码在js执行完同步代码之后才能执行。

setTimeout为什么不能恰到好处的执行呢,这是因为定时触发器线程只是在时间到了之后,把应该执行的函数进行封装放到队列里面而已,具体什么时候执行还得看之前队列含有多少消息没有被处理。

gui渲染线程与js执行引擎的交互机制

上面说了3个执行线程与js执行引擎的交互,这个基本上没有问题了,这下说说渲染与js代码之间的交互。

在刚开始写js代码时代,肯定遇到过js代码执行性能问题,比如页面直接就不动弹了半天,这个时候其实可以得出来一个结论:js执行的时候,渲染是阻塞的,之后查了资料,发现这个定义更准确的说法是:js执行引擎的线程和gui渲染线程是互斥的

这也能解释为什么js执行时间长后渲染不动的问题了;那么一个新的问题来了,如果是这样的话,那么渲染引擎肯定就不能渲染,至少在js队列不空的情况下,根本没有机会渲染的,那么就可以做一个代码不断的使用setInternal不断的往队列里面填消息。事实真的是这样吗?

肯定不是这样的,实际的浏览器没有是这样的,那么到底是哪块让js引擎和gui执行引擎的线程进行切换的,同步代码肯定不行,那么就是队列这块了,肯定不是队列为空的情况切换的,因为实际的js代码在改了之后基本上就渲染了,那么基本上确定,是在每一次消息之间执行的,因为js代码在执行的时候是同步的,做了这个假设之后,再查了大量的资料,有一篇文章是这样描述的,在每次执行完一个消息之后,马上切换到渲染线程执行渲染效果,然后渲染完成再切换js代码执行取下一个消息。

至此渲染和js代码执行的交互就了解了。(渲染线程是每次都需要切换的吗?这个已经属于性能优化内容了,就暂时不了解了)

posted @ 2018-03-11 17:15  asdfzxcvqwer  阅读(2148)  评论(1编辑  收藏  举报