
最近在学前端基础,今天梳理一下javascript的运行机制
只是简单理解,完全没入门那种~
首先必须记录的事Javascript是单线程的,目的是简化和用户的交互逻辑,从而不会出现严重的并发问题。
但是js脚本可以创建多个线程,但是创建的子线程受到主线程控制,同时不能操作DOM。
相关进程和线程
在浏览器中加载页面主要用到4个进程:
- 主进程:(
Browser进程)负责页面展示和资源下载等 GPU进程:负责3D图示绘图- 第三方插件进程:负责第三方插件的处理
- 渲染进程:(
Render进程),负责js执行,页面渲染等功能
其中渲染进程中又包括:
GUI渲染进程Js引擎线程- 事件循环线程
- 定时器线程
http异步线程- …
这里主要看渲染进程的相关线程
GUI渲染线程
主要处理的事情包括:
- 首先浏览器会解析
html代码(实际上html代码本质是字符串)转化为浏览器认识的节点,生成DOM树,也就是DOM Tree - 然后解析
css,生成CSSOM(CSS规则树) - 把
DOM Tree和CSSOM结合,生成Rendering Tree(渲染树)
注意其中存在重绘和回流:
如果修改了一些元素的颜色或者背景色,页面就会重绘(
Repaint),如果修改元素的尺寸,页面就会回流(Reflow),当页面需要Repaing和Reflow时GUI多会执行,进行页面绘制。
Js引擎线程
负责解析和执行js代码,浏览器同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的。
Js线程会阻塞渲染线程,因此<script>标签和其他DOM标签是顺序执行的,一旦执行到<script>标签就会立即执行,所以一般我们把<script>标签放在·body的最后
事件循环线程
用来控制事件的循环,维护和管理一个任务队列(task queue)。
下面会讲到关于事件队列的用法
定时器线程
单独用来计时,计时完成将定时器执行的操作添加到事件任务队列尾。
异步请求线程
执行到一个http异步请求时,便把异步请求事件添加到异步请求线程,等待响应;并把回调函数添加到事件队列,等待js引擎线程执行
Eventloop
Eventloop其实是Js的执行机制,表示了线程之间的协作关系
因为js是单线程,因此任务的执行只能顺序执行,为了将耗时的任务分离出来,在js中实现了两种任务类型,同步任务和异步任务。
- 所有同步任务在主线程上执行,形成执行栈
- 任务队列(task queue,就是由事件循环线程维护)负责存放异步任务的运行结果
- 执行栈的同步任务执行完成后会读取任务队列,将对应的异步任务加入执行栈执行
- 上述操作不断循环往复
诸如此图

注意一句话:
javascript的执行和运行有很大的区别,javascript在不同的环境下,比如node,浏览器,Ringo等等,执行方式是不同的。而运行大多指javascript解析引擎,是统一的。
定时器
定时器是一个相当特殊的存在,任务队列中不仅可以放普通事件,也可以放定时事件。
主要由setTimeout()和setInterval()两个函数完成
值得注意的是
定时器不会完全按照规定时间执行
- W3C标准规定
setTimeout中最小的时间周期是4毫秒,凡是低于4ms的时间间隔都按照4ms来处理。因此代码不会完全精确按照所定时间执行 - 主线程执行到定时器后,会把定时任务交给定时器线程执行,等到时间了,定时器所要执行的操作会放到任务队列末尾,因此不一定立即执行
- W3C标准规定
setInterval存在累计效应:如果定时器里面的代码执行所需的时间大于定时器的执行周期,会导致有些事件丢失可以使用
setTimeout()代替setInterval()1
2
3
4
5
6var say = function() {
setTimeout(say, 1000)
console.log('hello world')
}
setTimeout(say, 1000)
剩下的以后再总结…