浏览器中Javascript的运行机制

EvenLoop究竟是如何实现的

Posted by RyanYang on November 25, 2020
Javascript语言详解,第二篇   同时也是浏览器架构的第一篇

简单的Javascript

Javascript是一门weird language。它在某些地方以某种方式运行着,但你就是无法完全、彻底理解它。

对于C/C++/Java这样的静态/编译型语言(强类型语言),我们清楚它是由gcc通过编译将源代码转换为二进制代码,当运行程序的时候,连接器把程序从硬盘复制到内存中并且运行。即使是python这样的动态/解释型语言(弱类型语言),也拥有自己特定的解释器把源代码转换成字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。这一切都显得非常直观。

但Javascript最初是为了实现更为复杂的网页功能,而以一种浏览器脚本语言的形式出现,这也意味着它的运行机制都与浏览器紧密相关,因此若想彻底理解Javascript的运行机制,势必要对浏览器有一定了解,这也是本专题的目的所在。

以下均以Chrome为标准

首先看一段代码

1
2
3
4
5
6
7
var a = 1;
var b = 2;
function add(a,b){
    return a+b
}
var c = add(a,b);
console.log(c)

毫无疑问,输出3,运行机制是:

  • 运行前:函数声明(function add),变量声明(var a;var b; var c)
  • 运行时:a=1;b=2;c= add(a,b);console.log()

即使加上作用域和闭包和this指针概念,会使得代码分析起来更复杂一些,但总的来说,还是符合我们对解释型语言直观的印象:从上到下,逐行解释。

异步回调的Javascript

可是当涉及到异步回调函数时,这一切就变得很诡异了

1
2
3
var a = 0;
setTimeout(()=>{a++},0)
console.log(a);

控制台会输出什么, 0 or 1?事实上它会输出0,但当我们查看a的值时已经变成1了。

截屏2020-11-25 15.03.40

很难接受,但我们明白了:即使setTimeout为0,它也会在“当前代码”执行完毕之后再去执行其中的回调函数。

但Javascript不是以单线程的形式运行的吗,它是如何做到一边等(或者发出Http请求),一边运行之后的代码呢?

V8 和 Chrome

这里要理清一个关系:在Chorme中,Javascript的runtime environment是V8,这是一个以单线程的形式执行Js代码的解释器,它大概长这样:

截屏2020-11-25 15.14.29

heap用来分配对象,并把引用(地址)保存在栈中,stack用来分配基础数据类型(按值访问)和调用函数,关于内存分配之后再写一篇文章专门分析,这里着重关注函数调用。

而在V8 engine中,是没有setTimeout(),DOM,Http 这些函数的,换句话说,这些都是浏览器提供给我们的api,并不是在V8中运行的!

因此,一个更为完整的浏览器运行Javascript的框架实际长这样:

截屏2020-11-25 15.22.30

这里WebAPIs是一个统称,实际上可能包括网络进程(ajax),渲染进程(DOM),callback queue也分为多个:macro queue, micro queue, repaint queue。

在Javascript运行时,Eventloop是按下面的逻辑进行的:

eventloop1

在解析HTML时,

  • 每当遇到一个<script>标签,V8添加一个Macro taskexec stack中,也可以理解为main函数。
  • 当遇到调用api(web api / third api)时,Chrome会有专门的进程执行代码,同时main函数继续往下执行。
  • 当前main函数执行完毕后,查看micro task中是否有微任务需要执行,如果有,执行完全部。
  • 检查是否需要repaint, 如果需要,首先执行animate,再重绘
  • 检查marcro stack中是否有任务需要执行(setTimeout, ajax的回调函数),如果有,取出一个执行
  • 重复循环

因此,在task queue的优先级上,我们可以认为:

micro queue > repain queue > macro queue

这里留下了许多细节问题:

  • 为什么在marcro queue的基础上还需要micro queue?如何界定这两种任务?
  • 浏览器的api是如何执行的?
  • 浏览器具体是怎样解析HTML,CSS,JS的?
  • 浏览器是如何渲染的?

之后会有一篇文章,完整的解释浏览器是如何从服务器发来的HTML文件解析、绘制、执行出整个网站的,并针对以上问题进一步深入分析。