Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
shaodahong opened this issue Mar 8, 2017 · 12 comments
Open

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

shaodahong opened this issue Mar 8, 2017 · 12 comments
Labels

Comments

@shaodahong
Copy link
Owner

shaodahong commented Mar 8, 2017

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

总结

  • 千万不要使用evalwith
  • 减少属性或方法在原型链中寻找的链数
  • 变量被赋值后避免改变其数据类型(需要重编译)
  • 能用正则尽量用正则进行操作
  • 避免深层次的作用域嵌套
  • substring也会很快, O(1)
  • 避免造成稀疏数组var arr = []; arr[10000] = 1;
  • 迭代效率for>reduce>for in
  • 函数调用效率f()> f.call()> f.apply(),并且arguments也是很慢的,但是可变
  • 判断效率稠密>if>稀疏
  • 避免使用throw/catch
@shaodahong shaodahong changed the title 如何让你的JS更快 深入JS引擎:如何让你的JS更快 Mar 8, 2017
@xxmyjk
Copy link

xxmyjk commented Mar 9, 2017

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

@shaodahong
Copy link
Owner Author

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

@MarvinWilliam
Copy link

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

@shaodahong
Copy link
Owner Author

shaodahong commented Mar 9, 2017

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

@MarvinWilliam
Copy link

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

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

@shaodahong
Copy link
Owner Author

shaodahong commented Mar 10, 2017

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

@MarvinWilliam
Copy link

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

@FailLone
Copy link

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

@justjavac
Copy link

justjavac commented Mar 15, 2017

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

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

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

@shaodahong
Copy link
Owner Author

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

@shaodahong
Copy link
Owner Author

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

@macc6579
Copy link

macc6579 commented Mar 30, 2022

感谢楼主!收获很大~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants