JavaScript 배열의 진화와 성능 분석

小云云
풀어 주다: 2018-02-09 13:48:11
원래의
1164명이 탐색했습니다.

시작하기 전에 이 글은 JavaScript 배열의 기본을 설명하기 위한 것이 아니며 구문 및 사용 사례를 다루지도 않는다는 점을 명시해야 합니다. 이 기사에서는 메모리, 최적화, 구문 차이, 성능 및 최근 발전 사항에 대해 자세히 설명합니다. 이 기사에서는 주로 JavaScript 배열의 발전과 성능 분석을 소개합니다. 이 기사에서는 메모리, 최적화, 구문 차이, 성능 및 최근 발전에 대해 자세히 설명합니다. 도움이 필요한 친구들이 참고할 수 있고, 모두에게 도움이 되기를 바랍니다.

JavaScript를 사용하기 전에는 이미 C, C++, C#에 익숙했습니다. 많은 C/C++ 개발자와 마찬가지로 JavaScript에 대한 나의 첫인상은 좋지 않았습니다.

배열이 주된 이유 중 하나입니다. JavaScript 배열은 연속적이지 않으며 해시 맵이나 사전처럼 구현됩니다. 나는 이것이 약간 B 수준 언어라고 생각하며 배열 구현은 단순히 부적절합니다. 그 이후로 JavaScript와 그에 대한 나의 이해가 많이 바뀌었습니다.

JavaScript 배열이 실제 배열이 아닌 이유

JavaScript에 대해 이야기하기 전에 먼저 Array가 무엇인지부터 살펴보겠습니다.

배열은 특정 값을 보유하는 데 사용되는 연속적인 메모리 위치 시퀀스입니다. "연속적"(또는 연속적)이라는 강조점을 주목하는 것이 중요합니다.

위 그림은 배열이 메모리에 저장되는 방식을 보여줍니다. 이 배열은 4개의 요소를 보유하며 각 요소는 4바이트입니다. 전체적으로 16바이트의 메모리 영역을 차지합니다.

tinyInt arr[4];를 선언한다고 가정하면 할당된 메모리 영역의 주소는 1201부터 시작합니다. arr[2]를 읽으려면 수학적 계산을 통해 arr[2]의 주소만 얻으면 됩니다. 1201 + (2 X 4)를 계산하려면 1209부터 직접 읽기 시작하세요.

JavaScript의 데이터는 연결된 목록과 같은 다양한 데이터 구조를 사용하여 구현할 수 있는 해시 맵입니다. 따라서 JavaScript var arr = new Array(4)에서 배열을 선언하면 컴퓨터는 위에 표시된 것과 유사한 구조를 생성합니다. 프로그램이 arr[2]를 읽어야 하는 경우 1201부터 시작하는 주소 지정을 순회해야 합니다.

위의 빠른 JavaScript 배열과 실제 배열의 차이점. 분명히 수학적 계산은 연결 목록을 순회하는 것보다 빠릅니다. 이는 긴 배열의 경우 특히 그렇습니다.

JavaScript 배열의 진화

친구들이 사준 256MB 메모리 컴퓨터가 너무 부러웠던 시절을 기억하시나요? 오늘날 8GB RAM은 어디에나 있습니다.

마찬가지로 JavaScript 언어도 많이 발전했습니다. V8과 SpiderMonkey부터 TC39와 웹 사용자의 증가에 이르기까지 엄청난 노력으로 인해 JavaScript는 세계적 수준의 필수품이 되었습니다. 대규모 사용자 기반이 있으면 성능 개선은 당연히 어려운 요구 사항입니다.

사실 최신 JavaScript 엔진은 배열이 동종인 경우(모든 요소가 동일한 유형인 경우) 배열에 연속 메모리를 할당합니다. 좋은 프로그래머는 JIT(Just-In-Time 컴파일러)가 c 컴파일러 스타일 계산을 사용하여 요소를 읽을 수 있도록 항상 배열이 동종인지 확인합니다.

그러나 다른 유형의 요소를 동종 배열에 삽입하려는 경우 JIT는 전체 배열을 분해하고 이전 방식으로 다시 만듭니다.

그래서 코드가 나쁘지 않다면 JavaScript Array 객체는 배후에서 실제 배열로 유지되며 이는 현대 JS 개발자에게 매우 중요합니다.

또한 ES2015/ES6에 이어 어레이도 더욱 진화했습니다. TC39는 형식화된 배열(Typed Arrays)을 도입하기로 결정하여 ArrayBuffer를 갖게 되었습니다.

ArrayBuffer는 우리가 마음대로 작동할 수 있도록 연속 메모리를 제공합니다. 그러나 직접적으로 메모리를 조작하는 것은 여전히 ​​너무 복잡하고 낮은 수준입니다. 그래서 ArrayBuffer를 처리하는 뷰가 있습니다. 이미 몇 가지 보기를 사용할 수 있으며 앞으로 더 많은 보기가 추가될 예정입니다.

var buffer = new ArrayBuffer(8);
var view  = new Int32Array(buffer);
view[0] = 100;
로그인 후 복사

WebGL 이후 고성능의 효율적인 형식 배열이 도입되었습니다. WebGL 작업자는 바이너리 데이터를 효율적으로 처리하는 방법이라는 큰 성능 문제에 직면합니다. 또는 SharedArrayBuffer를 사용하여 여러 웹 작업자 프로세스 간에 데이터를 공유하여 성능을 향상시킬 수 있습니다.

간단한 해시 맵에서 이제 SharedArrayBuffer까지, 정말 멋지죠?

기존 스타일 배열과 형식화된 배열: 성능

우리는 이전에 JavaScript 배열의 발전에 대해 논의했습니다. 이제 최신 배열이 얼마나 많은 이점을 가져올 수 있는지 테스트해 보겠습니다. 다음은 Node.js 8.4.0을 사용하여 Mac에서 실행한 몇 가지 마이크로 테스트 결과입니다.

이전 스타일 배열: Insert

var LIMIT = 10000000;
var arr = new Array(LIMIT);
console.time("Array insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.timeEnd("Array insertion time");
로그인 후 복사

소요 시간: 55ms

Typed Array:插入
var LIMIT = 10000000;
var buffer = new ArrayBuffer(LIMIT * 4);
var arr = new Int32Array(buffer);
console.time("ArrayBuffer insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.timeEnd("ArrayBuffer insertion time");
로그인 후 복사

소요 시간: 52ms

문지르세요, 무엇을 볼 수 있나요? 이전 스타일의 배열과 ArrayBuffer의 성능은 동일합니까? 아니 아니 아니. 앞서 언급했듯이 최신 컴파일러는 내부적으로 동일한 요소 유형의 기존 배열을 메모리 연속 배열로 변환할 수 있을 만큼 똑똑합니다. 이것이 바로 첫 번째 예의 경우입니다. new Array(LIMIT)를 사용함에도 불구하고 해당 어레이는 여전히 최신 어레이로 존재합니다.

그런 다음 첫 번째 예를 수정하고 배열을 이종 배열(요소 유형이 완전히 일관되지 않음)로 변경하여 성능 차이가 있는지 확인합니다.

旧式数组:插入(异构)
var LIMIT = 10000000;
var arr = new Array(LIMIT);
arr.push({a: 22});
console.time("Array insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.timeEnd("Array insertion time");
로그인 후 복사

소요 시간: 1207ms

改变发生在第 3 行,添加一条语句,将数组变为异构类型。其余代码保持不变。性能差异表现出来了,慢了 22 倍。

旧式数组:读取

var LIMIT = 10000000;
var arr = new Array(LIMIT);
arr.push({a: 22});
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
var p;
console.time("Array read time");
for (var i = 0; i < LIMIT; i++) {
//arr[i] = i;
p = arr[i];
}
console.timeEnd("Array read time");
로그인 후 복사

用时:196ms

Typed Array:读取
var LIMIT = 10000000;
var buffer = new ArrayBuffer(LIMIT * 4);
var arr = new Int32Array(buffer);
console.time("ArrayBuffer insertion time");
for (var i = 0; i < LIMIT; i++) {
arr[i] = i;
}
console.time("ArrayBuffer read time");
for (var i = 0; i < LIMIT; i++) {
var p = arr[i];
}
console.timeEnd("ArrayBuffer read time");
로그인 후 복사

用时:27ms

结论

类型化数组的引入是 JavaScript 发展历程中的一大步。Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,这些是类型化数组视图,使用原生字节序(与本机相同)。我们还可以使用 DataView 创建自定义视图窗口。希望未来会有更多帮助我们轻松操作 ArrayBuffer 的 DataView 库。

JavaScript 数组的演进非常 nice。现在它们速度快、效率高、健壮,在内存分配时也足够智能。

相关推荐:

实例详解javascript数组去重的几种思路

JavaScript数组去重的几种方法分享

全面解析Javascript数组方法

위 내용은 JavaScript 배열의 진화와 성능 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿