shaodahong / dahong

个人技术随笔
https://biewen.me/
129 stars 17 forks source link

深入JS引擎:如何让你的JS更快 #5

Open shaodahong opened 7 years ago

shaodahong commented 7 years ago

qq20170308-085413

Know Your Engines

How to Make Your JavaScript Fast

看到了一篇旧文,是Mozilla公司的JS引擎工程师Dave的PPT,很多JS开发者都知道JS的效率很低,虽然JS无类型的特性让我们代码写的很爽,比如

var a = '22222';
a = 9;

我们根本不用管a初始的类型是string还是number,直接赋上我们想要的值就行,但是js引擎处理这些无类型的代码却并不轻松,当然这在JIT之前,但是JIT也并不是万能的

qq20170308-090852

要处理这样一段代码x = y + z; JS引擎处理无类型的代码要进行一个boxed(装箱)和unbox(解箱)的行为 要处理这样一段代码

  1. 从内存中读取x = y + z的操作符
  2. 从内存中读取y、z并装箱
  3. 检查y、z的类型并确定操作
  4. y、z解箱拿出
  5. 执行操作
  6. x装箱
  7. x装箱完毕后将x写入内存

看到上面的JS引擎处理代码的步骤,一眼就能看出其实我们想要的就是第五步,我们写代码不就是想让引擎帮我们执行操作么,但是JS无类型的特性让引擎不得不进行一些boxed和unbox行为,有了JIT之后

qq20170308-093455

  1. 从内存中读取x = y + z的操作符
  2. 从内存中读取y、z并装箱
  3. 检查y、z的类型并确定操作
  4. y、z解箱拿出
  5. 执行操作
  6. x装箱
  7. x装箱完毕后将x写入内存

1,2两步CPU帮我们做了,第7步JIT将代码保存到寄存器里面去 通常情况下JIT帮我们快速的编译代码,并且正则有专门的JIT编译,所以正则通常比手动搜索要快

IC(inline caching)

我们要找到一个obj里面叫a的属性,我们知道JS对象是基于prototype的,所以会一层链一层链的往上找,这是非常慢的,但是一旦找到了,获得属性的值是非常快的 所以有对Object处理的一个mini JIT,称它为IC,IC会为对象首次搜索后建立cache

总结

xxmyjk commented 7 years ago

较新版本的V8已经对throw/try-catch进行了优化, 具体可以看老司机 @justjavac 的博客, 戳戳戳

shaodahong commented 7 years ago

@xxmyjk 并且现在的JIT把boxed和unbox的完善了,直接执行操作了,感谢提供的博客,知识很好

MarvinWilliam commented 7 years ago

关于总结的第三点,请问下,变量赋null之后再进行赋值,这样算不算改变了数据类型?

shaodahong commented 7 years ago

@MarvinWilliam 如果赋值的是对象,不算,null本身也是对象,且是原型链的最顶层

MarvinWilliam commented 7 years ago

@Redshao 哦,明白了. 我看了下原始类型有String,Number,Boolean,Symbol.也就是说初始化的时候都应该用这几个类型的值.

那如果我们未对变量初始化,那就是undefined了,这个在赋值之后应该不算改变数据类型吧?

shaodahong commented 7 years ago

@MarvinWilliam string number boolean undefined null object和ES6的symbol构成了JS的数据类型,undefined和null一般都表示空值,一个变量声明但未定义这时候他的数据类型就是undefined,又或者一个function没有return值,那么这个function的返回值也是undefined,很抱歉我上面的理解错了,一般undefined用来占位,等待被合适的值填充,而null代表此处不应该有值,希望没有误解到你

MarvinWilliam commented 7 years ago

@Redshao 完全明白了.谢谢. : )

FailLone commented 7 years ago

请问“判断效率稠密>if>稀疏”具体是指什么?

justjavac commented 7 years ago

感谢 @xxmyjk 提到我的博客,但是我的博客并没有同步更新 V8 的知识。至于提到的 throw/catch 已经可以优化,是在最新的 V8 实现中,使用 TurboFan 引擎替换了 Crankshaft。

推荐我专栏中的两篇文章吧:

我之所以开始写 V8 专栏,就是因为网站关于 V8 的文章都过于古老,等到翻译成中文,就更古老了。但是 V8 的发展非常迅速,可能是因为 JS 发展太过迅速了吧。包括引入了解释器(之前 V8 没有解释器,只有通用编译器和优化编译器),更换了新的优化引擎,增加了对 wasm 的支持等。。。。

shaodahong commented 7 years ago

@FailLone 判断的效率是指你要判断对象的数据稠密度,稀疏的数据中显示的个数不代表所拥有的真实数据,所以查找的效率上就低,数据稠密用switch的效率比if要高,最差的就是稀疏的数据

shaodahong commented 7 years ago

@justjavac 是的,这是一篇比较老的PPT,近两年JavaScript的开发者以倍数增长,刺激引擎的更新乃至迭代不可避免,只是很多JSer包括我自己知其然却不知其所以然,所以看到一些好的文章拿出来当做一个读后笔记

macc6579 commented 2 years ago

感谢楼主!收获很大~