关于js运行机制的简单理解


        

最近在学前端基础,今天梳理一下javascript的运行机制

只是简单理解,完全没入门那种~

首先必须记录的事Javascript是单线程的,目的是简化和用户的交互逻辑,从而不会出现严重的并发问题。

但是js脚本可以创建多个线程,但是创建的子线程受到主线程控制,同时不能操作DOM

相关进程和线程

在浏览器中加载页面主要用到4个进程:

  1. 主进程:(Browser进程)负责页面展示和资源下载等
  2. GPU进程:负责3D图示绘图
  3. 第三方插件进程:负责第三方插件的处理
  4. 渲染进程:(Render进程),负责js执行,页面渲染等功能

其中渲染进程中又包括:

  • GUI渲染进程
  • Js引擎线程
  • 事件循环线程
  • 定时器线程
  • http异步线程

这里主要看渲染进程的相关线程

GUI渲染线程

主要处理的事情包括:

  1. 首先浏览器会解析html代码(实际上html代码本质是字符串)转化为浏览器认识的节点,生成DOM树,也就是DOM Tree
  2. 然后解析css,生成CSSOMCSS规则树)
  3. DOM TreeCSSOM结合,生成Rendering Tree(渲染树)

注意其中存在重绘和回流:

如果修改了一些元素的颜色或者背景色,页面就会重绘(Repaint),如果修改元素的尺寸,页面就会回流(Reflow),当页面需要RepaingReflow时GUI多会执行,进行页面绘制。

Js引擎线程

负责解析和执行js代码,浏览器同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的。

Js线程会阻塞渲染线程,因此<script>标签和其他DOM标签是顺序执行的,一旦执行到<script>标签就会立即执行,所以一般我们把<script>标签放在·body的最后

事件循环线程

用来控制事件的循环,维护和管理一个任务队列(task queue)。

下面会讲到关于事件队列的用法

定时器线程

单独用来计时,计时完成将定时器执行的操作添加到事件任务队列尾。

异步请求线程

执行到一个http异步请求时,便把异步请求事件添加到异步请求线程,等待响应;并把回调函数添加到事件队列,等待js引擎线程执行

Eventloop

Eventloop其实是Js的执行机制,表示了线程之间的协作关系

因为js是单线程,因此任务的执行只能顺序执行,为了将耗时的任务分离出来,在js中实现了两种任务类型,同步任务异步任务。

  • 所有同步任务在主线程上执行,形成执行栈
  • 任务队列(task queue,就是由事件循环线程维护)负责存放异步任务的运行结果
  • 执行栈的同步任务执行完成后会读取任务队列,将对应的异步任务加入执行栈执行
  • 上述操作不断循环往复

诸如此图

Event Loop

注意一句话:

javascript的执行和运行有很大的区别,javascript在不同的环境下,比如node,浏览器,Ringo等等,执行方式是不同的。而运行大多指javascript解析引擎,是统一的。

定时器

定时器是一个相当特殊的存在,任务队列中不仅可以放普通事件,也可以放定时事件。

主要由setTimeout()setInterval()两个函数完成

值得注意的是

  1. 定时器不会完全按照规定时间执行

    • W3C标准规定setTimeout中最小的时间周期是4毫秒,凡是低于4ms的时间间隔都按照4ms来处理。因此代码不会完全精确按照所定时间执行
    • 主线程执行到定时器后,会把定时任务交给定时器线程执行,等到时间了,定时器所要执行的操作会放到任务队列末尾,因此不一定立即执行
  2. setInterval存在累计效应:如果定时器里面的代码执行所需的时间大于定时器的执行周期,会导致有些事件丢失

    可以使用setTimeout()代替setInterval()

    1
    2
    3
    4
    5
    6
    var say = function() {
    setTimeout(say, 1000)
    console.log('hello world')
    }

    setTimeout(say, 1000)

剩下的以后再总结…

参考链接

JavaScript 运行机制详解:再谈Event Loop

js运行原理与机制

分享到: