一 js 运行机制
js 执行引擎
经常看文章的说到 js 是带线程的, 其实这个说法非常的模糊, 准确的是 js 执行引擎是单线程的, js 执行引擎就是 js 代码的执行器, 有了这个概念就可以下来说说 js 是如何运行的了
js 代码如何运行?
在 js 代码执行的时候, js 的代码是按照顺序执行的, 从上到下, 这个时候是同步的, 不过, 有几个例外:
异步的网络请求
事件绑定事件监听器
时间触发函数
我们模拟一下, js 引擎遇到这三类代码的情况:
js 执行的好好的, 正在顺序执行代码, 这个时候呢, 遇到了异步的网络请求的代码, 这个时候, 直接 js 代码调用之后, 就继续执行之后的 js 代码了, 并没有等待网络请求的结果, js 代码执行是单线程的 (不考虑 h5), 那么肯定异步网络请求调用之后, 肯定不是 js 执行引擎管理了, 问题一: 谁在等待, 谁之后通知 js 执行引擎结果, 毕竟是 js 代码就得 js 引擎是执行
有了第一个问题, 我们已经知道肯定有其它的东西参与了上面的事情了, 先放着, 之后呢 js 有欢乐的往下执行, 遇到了事件绑定和事件监听函数, 哦, 这个 js 调用之后, 也是继续往下走的, 并没有调用那些函数之类的, 我们知道, 事件函数只有在事件触发的时候会起作用, js 代码 js 执行引擎执行那么问题二: 谁把事件关联的函数保存的, 以便接收事件触发选择正确的事件处理函数, 通知 js 执行引擎?
js 在遇到 setTimeout 和 setInternal 函数的时候, 也是不直接执行, 然后处理之后的代码的, 那么问题三: 谁在监视时间流逝选择合适的触发函数通知 js 引擎执行的?
以上 3 点是在自己学习 js 的运行机制和 js 执行引擎的时候, 遇到了 3 个问题, 那么 3 个问题其中的 js 执行 js 代码, 但是监视肯定不是 js 执行引擎, 答案如下:
异步网络请求线程
事件触发线程
定时触发器线程
以上 3 个线程是独立于 js 引擎之外, 帮助处理这 3 类代码的, 所以啊, 千万不要认为 js 引擎什么都做, 加上 gui 渲染线程, js 执行引擎线程, 5 个线程齐了
以上我们了解了 js 执行的代码和 3 个额外的线程协助下, js 执行代码构建了完备的环境了, 但是 js 执行引擎是如何执行这 3 类线程给的函数的, 答案是队列 (暂且叫做 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 代码执行的交互就了解了 (渲染线程是每次都需要切换的吗? 这个已经属于性能优化内容了, 就暂时不了解了)
来源: https://www.cnblogs.com/fenqi/p/8544818.html