>웹 프론트엔드 >JS 튜토리얼 >브라우저는 얼마나 빠를 수 있나요?

브라우저는 얼마나 빠를 수 있나요?

伊谢尔伦
伊谢尔伦원래의
2016-12-01 09:27:43982검색

React.js는 효율적인 UI 렌더링으로 유명합니다. 중요한 이유 중 하나는 가상 DOM을 유지한다는 것입니다. React.js는 diff 알고리즘을 사용하여 브라우저의 최소 작업을 결정합니다. DOM을 수동으로 대량 수정하여 발생하는 성능 손실을 방지합니다. 잠깐, 분명히 중간에 레이어가 추가되었는데 결과가 더 빨라지는 이유는 무엇입니까? React.js의 핵심 아이디어는 DOM 작업이 느리기 때문에 전반적인 성능 향상을 위해 DOM 작업을 최소화해야 할 수도 있다는 것입니다. DOM 작업이 느리다는 것은 모두에게 분명하지만 다른 JavaScript 스크립트는 빠르게 실행되어야 합니까?

브라우저는 얼마나 빠를 수 있나요?

V8이 나오기 전에는 이 질문에 대한 대답은 '아니오'였습니다. Google의 초기 비즈니스 모델은 웹을 기반으로 했습니다. Gmail과 같은 매우 복잡한 웹 앱을 브라우저에 작성할 때는 브라우저의 견딜 수 없는 성능을 인식할 수 없었는데, 이는 주로 JavaScript의 실행 속도가 너무 느리기 때문이었습니다. . 2008년 9월 Google은 JavaScript 엔진인 V8을 구축하여 이러한 상황을 바꾸기로 결정했습니다. V8을 탑재한 크롬 브라우저가 시장에 등장했을 때 그 속도는 당시 모든 브라우저에 비해 훨씬 뒤처졌습니다. 브라우저 성능의 전례 없는 개선으로 복잡한 웹 앱이 가능해졌습니다.

지난 7년 동안 브라우저 성능은 CPU 성능과 함께 계속해서 상승했지만, 2008년에 경험했던 획기적인 성장을 이룬 적은 없습니다. V8은 JavaScript의 성능을 그토록 향상시키기 위해 어떤 기술을 사용합니까?

V8 최적화

JavaScript를 더 빠르게 만드는 방법에 대해 이야기하려면 먼저 왜 느린지 이야기해야 합니다. 우리 모두 알고 있듯이 JavaScript는 Brendan Eich에 의해 일주일 넘게 개발되었습니다. Apple 팀이 4년 동안 작업한 결과인 현재 Swift와 비교하면 애초에 큰 기대를 해서는 안 됩니다. . 사실, Brendan Eich는 자신이 그러한 규모의 언어를 개발하고 있다는 사실을 깨닫지 못했습니다. 프로그래머가 글을 유연하게 작성할 수 있도록 그는 JavaScript를 약한 유형의 언어로 설계했으며, 개체의 속성은 런타임에 추가 및 삭제할 수 있습니다. 많은 사람들을 당황하게 만드는 상속, 다형성, 템플릿, 가상 함수, C++의 동적 바인딩과 같은 개념은 더 이상 JavaScript에 존재하지 않습니다. 그러면 누가 그 일을 하게 될까요? 당연히 JavaScript 엔진만 있습니다. 변수 유형을 모르기 때문에 런타임에 많은 유형 파생을 수행합니다. Parser가 작업을 완료하고 추상 구문 트리(AST)를 구축하면 엔진은 AST를 바이트코드(바이트코드)로 변환하고 실행을 위해 바이트코드 해석기에 넘겨줍니다. 성능을 가장 저하시키는 단계 중 하나는 인터프리터가 바이트코드를 실행하는 단계입니다. 그때를 돌이켜보면 통역능력이 낮다는 걸 다들 알고 계시지 않았나요? 사실, 이 설계를 한 이유는 당시 사람들이 일반적으로 JavaScript가 디자이너를 위해 개발된 언어(프론트엔드 엔지니어들이 냉정하다고 느끼나요?)로서 너무 높은 성능을 요구하지 않는다고 믿었기 때문입니다. 이는 비용 효율적이고 충족됩니다. 수요. .

V8이 하는 주요 작업은 엔진 속도를 저하시키는 이 부분을 제거하는 것입니다. AST에서 CPU 실행 가능 기계어 코드를 직접 생성합니다. 이러한 JIT(Just In Time) 컴파일 기술을 JIT(Just In Time)라고 합니다. 충분히 궁금하다면 '도대체 이게 어떻게 된 거지?'라는 자연스러운 생각이 들 것이다.

예를 들어보겠습니다.

function Foo(x, y) {
    this.x = x;
    this.y = y;
}
var foo = new Foo(7, 8);
var bar = new Foo(8, 7);
foo.z = 9;

속성 읽기

첫 번째는 데이터 구조입니다. 객체의 속성을 어떻게 색인화할 예정입니까? 우리는 이미 JSON의 key:value 데이터 구조에 너무 익숙하지만 메모리에서 키로 인덱싱할 수 있습니까? 메모리에서 값의 위치를 ​​결정할 수 있습니까? 물론 메모리의 각 키에 해당하는 값의 위치를 ​​저장하는 각 개체에 대한 테이블을 유지하는 한 가능합니다. 그렇죠?

여기서 함정은 각 개체에 대해 이러한 테이블을 유지해야 한다는 것입니다. 왜? C언어에서는 어떻게 되는지 살펴보겠습니다.

struct Foo {
    int x, y;
};
struct Foo foo, bar;
foo.x = 7;
foo.y = 8;
bar.x = 8;
bar.y = 7;
// Cant' set foo.z

대학 교과서를 잘 생각해보세요. foo.x와 foo.y의 주소는 직접 계산할 수 있습니다. 멤버 x, y의 타입이 정해져 있는데, foo.x = "Hello"는 자바스크립트에서는 완전 가능하지만 C언어에서는 불가능하기 때문이다.

  V8 不想给每个对象都维护一个这样的表。它也想让 JavaScript 拥有 C/C++ 直接用偏移就读出属性的特性。所以它的解决思路就是让动态类型静态化。V8 实现了一个叫做隐藏类(Hidden Class)的特性,即给每个对象分配一个隐藏类。对于 foo 对象,它生成一个类似于这样的类:

class Foo {
    int x, y;
}

  当新建一个 bar 对象的时候,它的 x 和 y 属性恰好都是 int 类型,那么它和 foo 对象就共享了这个隐藏类。把类型确定以后,读取属性就只是在内存中增加一个偏移的事情了。而当 foo 新建了 z 属性的时候,V8 发现原来的类不能用了,于是就会给 foo 新建一个隐藏类。修改属性类型也是类似。

  Inline caching

  由上可知,当访问一个对象的属性的时候,V8 首先要做的就是确定对象当前的隐藏类。但每次这样做的开销也很大,那很容易想到的另一个计算机中常用的解决方案,就是缓存。在第一次访问给定对象属性的时候,V8 将假设所有同一部分代码的其他对象也都使用了这个对象的隐藏类,于是会告诉其他对象直接使用这个类的信息。在访问其他对象的时候,如果校验正确,那么只需要一条指令就可以得到所需的属性,如果失败,V8 就会自动取消刚才的优化。上面这段话用代码来表述就是:

foo.x
# ebx = the foo object
cmp [ebx,<hidden class offset>],<cached hidden class>
jne <inline cache miss>
mov eax,[ebx, <cached x offset>]

  这极大提升了 V8 引擎的速度。

 随着 Intel 宣布 Tick-Tock 模型的延缓,CPU 处理速度不再能像之前一样稳步增长了,那么浏览器还能继续变快吗?V8 的优化是浏览器性能的终点吗?

  JavaScript 的问题在于错误地假设前端工程师都是水平不高的编程人员(如果不是,你应该不会读到这里),岂图让程序员写得舒服而让计算机执行得痛苦。在现代浏览器引擎已经优化到这个地步的时候,我们不禁想问:为什么一定是 JavaScript ?前端工程师是不是可以让出一步,让自己多做一点点事情,而让引擎得以更高效地优化性能?JavaScript 成为事实上的浏览器脚本标准有历史原因,但这不能是我们停止进步的借口。

  当 Web Assembly 正式宣布的时候,我才确定了不仅仅是我一个名不见经传的小程序员有这样的想法,那些世界上最顶级的头脑已经开始行动了。浏览器在大量需求的驱动下正在朝着一个高性能的方向前进,浏览器究竟可以有多快,2015 可能是这条路上另一个转折点。


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.