프런트엔드 성능 최적화를 위한 JS 최적화

소개

오늘날의 기술 세계에서 웹페이지든 애플리케이션이든 프런트엔드 개발은 의심할 여지 없이 중요합니다. 인터넷이 발전함에 따라 사용자는 웹 페이지의 성능과 로딩 속도에 대한 요구 사항이 점점 더 높아지고 있습니다. 프론트엔드 개발자로서 우리는 더 나은 성능 최적화를 위해 노력해야 합니다. 그 중 자바스크립트는 프론트엔드 개발의 핵심 언어로 웹 페이지 성능에 미치는 영향을 무시할 수 없습니다. 이 기사에서는 독자가 JavaScript 코드를 최적화하여 웹 페이지의 로딩 속도와 사용자 경험을 향상시키는 방법을 이해하도록 돕기 위해 일련의 기술과 방법을 통해 JavaScript 성능 최적화에 중점을 둘 것입니다. 이제 막 시작한 프론트엔드 개발자이시든, 이미 업계 경험이 있으신 베테랑이시든, 이 글을 통해 실무적인 기술을 배우실 수 있으며, 이 글이 여러분에게 도움과 영감을 줄 수 있기를 바랍니다. 프런트엔드 성능 최적화를 위한 JavaScript 최적화의 미스터리를 탐구해 보겠습니다.

1. 브라우저가 js 파일 프로세스를 로드합니다.

js 파일 리소스를 로드하는 브라우저의 프로세스는 다음 단계로 나눌 수 있습니다.

  1. 요청 시작 : 브라우저는 HTTP 요청을 보내 서버에서 js 파일 리소스를 얻습니다. 이 프로세스에는 네트워크 전송이 포함되며 네트워크 지연은 상대적으로 큰 오버헤드가 될 수 있습니다.

  2. 응답 수신 : 요청을 받은 후 서버는 js 파일의 내용이 포함된 응답 메시지를 반환합니다. 브라우저는 응답 헤더를 구문 분석하고 응답 본문을 수신하며, 이 프로세스에 필요한 시간은 js 파일의 크기와 네트워크 전송 속도에 따라 다릅니다.

  3. HTML 구문 분석 : 브라우저가 js 파일을 수신할 때 HTML 페이지에 해당 파일에 대한 참조가 있으면 브라우저는 HTML 구문 분석을 일시 중지하고 가능한 한 빨리 js 파일을 다운로드하여 구문 분석합니다. 이때 브라우저는 js 엔진을 실행하여 js 파일을 구문 분석하고 컴파일합니다. 이 프로세스에 걸리는 시간은 js 파일의 크기와 복잡성에 따라 다릅니다.

  4. js 코드 실행 : js 파일이 구문 분석되고 컴파일되면 브라우저는 js 코드를 실행합니다. js 코드의 실행 속도는 js 엔진의 성능과 코드의 복잡성에 따라 달라집니다. js 코드를 실행할 때 약간의 CPU 오버헤드가 발생할 수 있습니다.

  5. 페이지 업데이트 : js 코드가 페이지의 DOM 구조를 조작하는 경우 브라우저는 DOM 업데이트를 반영하기 위해 페이지를 다시 렌더링합니다. DOM 작업에 필요한 시간은 작업의 복잡성과 브라우저 성능에 따라 달라집니다.

일반적으로 js 파일을 로드하는 프로세스에는 네트워크 전송, 구문 분석 및 컴파일, 페이지 실행 및 업데이트와 같은 여러 단계가 포함되며 각 단계의 오버헤드는 파일 크기, 네트워크 속도, 코드 복잡성 대기 등 다양한 요소의 영향을 받습니다. .

2. 브라우저 로딩 js와 사진 비교

브라우저가 동일한 크기의 JS 리소스와 이미지 리소스를 로드할 때 일반적으로 JS 리소스를 로드하는 데 더 오랜 시간이 걸립니다 .

이는 JS 리소스를 로드하는 과정에 여러 단계가 있기 때문입니다.

  1. DNS 확인 : 브라우저는 도메인 이름 확인을 통해 서버의 IP 주소를 획득하고 리소스 위치 지정을 완료합니다.
  2. 연결 설정 : 브라우저는 3방향 핸드셰이크 프로세스를 포함하여 서버와의 TCP 연결을 설정합니다.
  3. Send request : 브라우저는 관련 리소스를 요청하기 위해 서버에 GET 요청을 보냅니다.
  4. 응답 수신 : 서버가 응답을 보내는데, 서버 속도 및 네트워크 상황에 따라 다소 시간이 걸릴 수 있습니다.
  5. 리소스 다운로드 : 응답이 수신되면 브라우저는 JS 리소스 다운로드를 시작합니다.
  6. 구문 분석 및 실행 : 다운로드가 완료된 후 브라우저는 JS 코드를 구문 분석하고 실행하기 시작합니다.

이미지 리소스 로딩 프로세스는 비교적 간단하며 주로 다음 단계를 포함합니다.

  1. DNS 확인 .
  2. 연결을 설정합니다 .
  3. 요청을 보냅니다 .
  4. 응답을 받습니다 .
  5. 리소스를 다운로드합니다 .

다운로드가 완료된 후에도 JS 리소스 로드는 여전히 구문 분석 및 실행이 필요하지만 이미지 리소스는 구문 분석 및 실행이 필요하지 않으므로 상대적으로 JS 리소스 로드에 시간이 많이 소요된다는 것을 알 수 있습니다 . 더 이상 .

특정 네트워크 환경 및 서버 응답 속도에 따라 다음 표는 다양한 로딩 단계에 대해 가능한 시간 소모적 비교표입니다.

단계 JS 리소스는 시간이 많이 걸립니다 시간이 많이 걸리는 이미지 리소스
DNS 확인 20ms 20ms
연결을 설정하다 30ms 30ms
요청 보내기 10ms 10ms
응답을 받다 50ms 50ms
리소스 다운로드 100ms 100ms
구문 분석 및 실행 200ms -
총 소요 시간 410ms 210ms

위 데이터는 참고용일 뿐이며 실제 시간 소모는 네트워크 상태, 서버 응답 속도, 캐싱 메커니즘 등의 요인에 의해 영향을 받습니다.

3. 총 리소스 로딩 시간 대비 브라우저가 로딩한 js 리소스의 비율

일반적으로 브라우저가 JS 리소스를 로드하는 데 필요한 시간은 전체 리소스를 로드하는 데 필요한 시간의 상당 부분을 차지합니다. 왜냐하면 JavaScript는 클라이언트 측에서 실행해야 하는 스크립팅 언어이고, 페이지의 상호 작용 및 기능 구현에 직접적인 영향을 미치기 때문에 JS 리소스를 로드하고 실행하는 데 시간이 많이 걸리기 때문입니다. 보통 10%~30% 사이

예를 들어 실제 웹사이트가 HTML 페이지, CSS 스타일시트, JS 파일로 구성되어 있다고 가정해 보겠습니다. 로드하는 동안 브라우저는 다음 순서로 진행됩니다.

  1. 먼저 브라우저는 HTML 페이지를 다운로드합니다. HTML 콘텐츠가 적기 때문에 이 프로세스가 더 빠릅니다.

  2. 다음으로, 브라우저는 HTML 페이지를 구문 분석하고 구문 분석 프로세스 중에 CSS 스타일 시트에 대한 참조를 찾습니다. 브라우저는 CSS 스타일 시트 파일 다운로드를 시작하고 다운로드가 완료된 후 이를 페이지에 적용합니다. 이 프로세스는 JS 리소스보다 빠릅니다.

  3. CSS 스타일이 로드된 후 브라우저는 계속해서 HTML 페이지를 구문 분석하고 JS 파일의 참조를 찾습니다. 이 시점에서 브라우저는 JS 파일 다운로드를 시작하고 다운로드가 완료된 후 JS 스크립트 로직을 실행합니다. JS 파일에는 일반적으로 복잡한 논리 처리와 가능한 비동기 작업 및 네트워크 요청이 포함되므로 JS 로딩 및 실행 시간이 더 길어질 수 있습니다.

요약하자면, 웹 사이트의 경우 브라우저가 JS 리소스를 로드하는 데 필요한 시간은 모든 리소스를 로드하는 데 필요한 시간의 상당 부분을 차지합니다. JS 스크립트는 페이지에서 상호 작용, 기능 구현 등 핵심 부분을 포함하는 중요한 역할을 하기 때문에 로드하고 실행하는 데 오랜 시간이 걸립니다. 일부 복잡한 웹사이트에서는 JS 리소스가 다른 리소스보다 로드하는 데 시간이 더 오래 걸릴 수도 있습니다.

페이지의 특정 상황은 각 리소스 로딩의 시간 할당 비율에도 영향을 미친다는 점에 유의해야 합니다. 예를 들어 웹 사이트의 주요 콘텐츠가 사진인 경우 사진 리소스의 로딩 시간은 더 길어질 수 있지만 JS 리소스의 로딩 시간은 상대적으로 짧습니다. 따라서 이 비율은 사이트마다 다릅니다.

4. v8의 컴파일 원리 개요

V8 은 코드 실행을 위해 V8에서 개발한 오픈 소스 JavaScript엔진 입니다 . 컴파일 원리는 적시 컴파일( ) 기술을 기반으로 합니다.GoogleJavaScriptJust-In-Time Compilation,JIT

V8 의 컴파일 과정은 분석 ( parsing), 최적화 ( optimization), 코드 생성 ( code generation) 의 세 단계로 나눌 수 있습니다 .

  1. 구문 분석 단계 :
    구문 분석 단계에서 V8은JavaScript 코드를 추상 구문 트리( Abstract Syntax Tree, )라는 데이터 구조로 구문 분석합니다 AST. 코드를 트리 구조로 표현하는 방식으로AST , 각 노드는 변수, 함수, 표현식 등 코드의 구성요소를 나타냅니다. 구문 분석 단계에서는 후속 최적화 단계를 위한 어휘 범위( )에 대한 정보도 구축합니다.lexical scope

  2. 최적화 단계 :
    최적화 단계는 V8 엔진의 핵심 부분입니다. V8은 코드가 실행되기 전에 최적화하는 Just-In-Time 컴파일( )이라는 기술을 사용합니다 Just-In-Time Compilation,JIT. V8은 코드의 실행 특성을 분석하여 코드의 유형과 동작을 식별하고 추론하려고 합니다. 이 정보를 기반으로 V8은inlining 인라인 함수( ), 쓸모 없는 코드 제거( dead code elimination), 네이티브 코드 생성( native code generation) 등과 같은 일련의 코드 최적화를 수행합니다. 이러한 최적화는 JavaScript코드 실행 효율성을 크게 향상시킬 수 있습니다.

  3. 코드 생성 단계 :
    코드 생성 단계에서 V8은 최적화된 코드를 기본 시스템에서 실행하기 위한 기계어 코드로 변환합니다. V8은Code Caching 컴파일된 코드를 캐시하고 후속 실행에서 직접 사용할 수 있는 캐시 실행( )이라는 기술을 채택하여 반복적인 컴파일을 방지하고 성능을 향상시킵니다.

V8 의 최적화는 JIT(Just-In-Time) 컴파일을 기반으로 한다는 점에 유의해야 합니다 . 이는 V8이 정적 단계에서 사전 최적화하는 것이 아니라 코드 실행 중에 동적으로 최적화한다는 것을 의미합니다. 런타임 시 코드 실행 특성을 수집함으로써 V8은 특정 실행 시나리오에 맞게 최적화될 수 있으며, 이를 통해 더 높은 실행 속도와 더 낮은 메모리 사용량을 제공합니다.

요약하면, V8JavaScript 의 컴파일 원리는 코드를 추상 구문 트리로 변환한 다음 최적화하고 최종적으로 기계어 코드를 생성하는 것 입니다 . 이 설계는 하드웨어 플랫폼의 장점을 최대한 활용하고 고성능 JavaScript실행 환경을 제공할 수 있습니다.

5. V8 컴파일 효율성을 향상시키기 위한 코드 레벨 최적화

1. 기능 최적화

V8의 컴파일 효율성을 향상시키기 위해 다음 측면에서 최적화할 수 있습니다.

1. 기능 크기 및 복잡성 감소

함수의 크기와 복잡성은 V8의 컴파일 효율성에 직접적인 영향을 미칩니다. 간결한 코드, 작은 함수 크기, 더 적은 수의 중첩 호출 계층을 갖춘 함수는 바이트코드 구문 분석 및 생성 시간을 줄일 수 있습니다.

  1. 기능 크기 줄이기:

    • 불필요한 코드 제거 : 함수 구현을 확인하고 사용하지 않는 변수, 중복 코드, 불필요한 제어 흐름을 제거합니다.
    • 큰 함수 분할 : V8 컴파일러가 각 함수를 더 빠르게 처리할 수 있도록 큰 함수를 여러 개의 작은 함수로 분할합니다.
    • 인라인 함수 사용 : 함수 호출의 오버헤드를 줄이기 위해 호출되는 위치에 짧은 함수를 인라인합니다.
  2. 기능 복잡성 감소:

    • 루프 중첩 감소 : 재귀 또는 리팩토링 알고리즘을 사용하여 단순화할 수 있는 다중 수준 중첩 루프 구조를 피합니다.
    • 공통 계산 추출 : 반복되는 계산을 추출하여 반복 작업의 실행 시간을 단축합니다.
    • 개체의 속성과 메서드 줄이기 : 불필요한 복잡성을 피하기 위해 개체의 속성과 메서드를 합리화하고 병합해 보세요.

2. 동적 기능 사용을 피하세요

컴파일할 때 V8은 인라인 최적화를 수행하기 위해 최선을 다합니다. 즉, 함수가 호출된 위치를 호출된 함수의 구현 코드로 대체하여 함수 호출의 오버헤드를 줄입니다. 그러나 함수가 eval()이나 Function()을 통해 함수를 동적으로 생성하는 등 동적 특성을 갖는 경우 V8은 인라인 최적화를 수행할 수 없으므로 컴파일 효율성이 저하됩니다.

V8의 컴파일 효율성을 향상시키기 위해 동적 기능의 사용을 피함으로써 컴파일 시간을 줄일 수 있습니다. 동적 기능은 코드에서 동적 유형의 사용, 변수 이름의 동적 구문 분석, 동적 바인딩 등을 나타냅니다. 컴파일하는 동안 V8은 이러한 동적 기능을 미리 해결할 수 없으므로 컴파일 시간이 늘어납니다.

다음은 동적 기능의 사용을 피함으로써 V8의 컴파일 효율성을 향상시키는 방법을 보여주는 실제 적용 사례입니다.

동적 문자열 연결 기능을 포함하는 JavaScript 애플리케이션이 있다고 가정해 보겠습니다. 이 함수의 입력은 객체 배열이며 객체의 속성 이름과 속성 값은 동적일 수 있습니다. 함수의 기능은 객체 배열의 속성 이름과 속성 값을 문자열로 연결하여 반환하는 것입니다.

function concatProperty(objArray) {
    
    
  let result = "";
  for (let obj of objArray) {
    
    
    for (let key in obj) {
    
    
      result += key + ": " + obj[key] + ", ";
    }
  }
  return result;
}

let objArray = [
  {
    
     name: "Alice", age: 25 },
  {
    
     name: "Bob", age: 30 },
  {
    
     name: "Charlie", age: 35 }
];

console.log(concatProperty(objArray));

이 예에서는 V8이 컴파일 타임에 속성 이름과 속성 값의 유형을 결정할 수 없도록 동적 속성 이름과 속성 값을 사용합니다. 이로 인해 V8은 런타임에 동적 분석 및 유형 추론을 수행하게 되며 이는 컴파일 속도에 영향을 미칩니다.

V8의 컴파일 효율성을 향상시키기 위해 몇 가지 최적화 기술을 사용할 수 있습니다. 첫째, 동적 속성 이름과 속성 값을 사용하지 않도록 노력할 수 있습니다. 위의 예에서 속성 이름과 속성 값의 유형이 고정되어 있다는 것을 알면 객체로부터 속성 이름과 속성 값을 동적으로 얻는 대신 정적 속성 이름과 속성 값을 사용할 수 있습니다. 이러한 방식으로 V8은 컴파일 타임에 속성 이름과 속성 값의 유형을 추론할 수 있어 런타임 시 동적 분석을 줄일 수 있습니다.

수정된 코드는 다음과 같습니다.

function concatProperty(objArray) {
    
    
  let result = "";
  for (let obj of objArray) {
    
    
    result += obj.name + ": " + obj.age + ", ";
  }
  return result;
}

let objArray = [
  {
    
     name: "Alice", age: 25 },
  {
    
     name: "Bob", age: 30 },
  {
    
     name: "Charlie", age: 35 }
];

console.log(concatProperty(objArray));

동적 기능의 사용을 피함으로써 V8의 컴파일 효율성을 향상시키고 런타임 시 동적 분석 및 유형 추론을 줄여 코드 실행 속도를 높일 수 있습니다. 이는 크고 복잡한 JavaScript 애플리케이션에 특히 중요합니다.

3. eval() 및 with 문을 피하세요.

eval() 및 with 문은 컴파일 단계에서 범위 체인에 변경을 발생시켜 V8이 정적 분석 및 최적화를 수행하기 어렵게 만듭니다. 컴파일 효율성을 높이려면 이러한 문을 최대한 사용하지 마세요.

  1. eval() 사용 방지: eval() 함수는 수신 문자열을 JavaScript 코드로 실행할 수 있지만 이로 인해 V8이 미리 컴파일 및 최적화되지 않아 성능에 영향을 미칠 수 있습니다. eval()을 사용하여 코드가 동적으로 실행되는 것을 방지하려면 함수 호출, 조건문 등과 같은 다른 대안을 사용하는 것을 고려하십시오.

  2. with 문을 사용하지 마세요. with 문은 새로운 범위를 생성하고 V8의 최적화 기능에 영향을 미칩니다. 코드 가독성과 성능을 보장하려면 기존의 변수 선언 및 액세스 방법을 사용하는 것이 좋습니다.

다음은 설명하기 위한 실제 적용 사례입니다.

eval() 함수와 with 문을 사용하여 동적 속성 액세스를 수행하는 다음 코드 조각을 고려하세요.

function getProperty(obj, prop) {
    
    
  with(obj) {
    
    
    return eval(prop);
  }
}

const obj = {
    
     foo: 10, bar: 20 };
const property = getProperty(obj, "foo");
console.log(property);

컴파일 효율성을 높이기 위해 다음과 같이 eval() 및 with 문을 사용하지 않도록 코드를 다시 작성할 수 있습니다.

function getProperty(obj, prop) {
    
    
  return obj[prop];
}

const obj = {
    
     foo: 10, bar: 20 };
const property = getProperty(obj, "foo");
console.log(property);

V8은 eval()과 구문을 사용하지 않고 객체의 속성에 직접 접근함으로써 코드를 미리 컴파일하고 최적화할 수 있어 성능이 향상됩니다. 이 방법은 훨씬 더 명확하고 이해하기 쉽습니다.

4. 엄격 모드 사용

엄격 모드에서 V8은 더 많은 정적 분석 및 최적화를 수행할 수 있으므로 컴파일 효율성이 향상됩니다. 엄격 모드는 "use strict" 지시어로 활성화됩니다.
엄격 모드를 사용하면 V8의 컴파일 효율성이 향상될 수 있습니다. 주로 엄격 모드의 코드가 더욱 표준화되고 간결해지기 때문에 불필요한 검사와 변환이 제거되어 V8의 작업 부하가 줄어들고 컴파일 속도가 향상되기 때문입니다.

다음은 Strict 모드를 사용하여 V8의 컴파일 효율성을 향상시키는 방법을 보여주는 실제 적용 사례입니다.

다음 내용을 포함하는 JavaScript 파일이 있다고 가정합니다.

"use strict";

const name = "John";
let age = 30;

function sayHello() {
    
    
  console.log("Hello, " + name + "! You are " + age + " years old.");
}

sayHello();

위 코드에서는 strict 모드("use strict")를 사용하고, 두 개의 변수 name과 age를 선언하고, sayHello 함수를 정의하여 인사말을 인쇄합니다.

엄격하지 않은 모드의 코드와 비교하여 엄격 모드를 사용하면 다음과 같은 이점이 있습니다.

  1. 오류 조기 식별: 엄격 모드에서는 선언되지 않은 변수를 선언할 수 없습니다. 그렇지 않으면 ReferenceError가 발생합니다. 이를 통해 개발자는 코드 초기에 오류를 찾아 디버깅 시간을 줄일 수 있습니다.

  2. 운영 효율성 향상: 엄격 모드에서는 JavaScript 엔진이 코드를 더 효과적으로 최적화할 수 있습니다. 예를 들어 eval 함수와 with 문은 엄격 모드에서 금지되며 이러한 기능은 종종 성능 저하로 이어집니다. 이러한 기능을 비활성화하면 V8 엔진이 보다 효율적으로 컴파일하고 최적화하여 실행 속도를 높일 수 있습니다.

엄격 모드를 사용하면 V8 컴파일러는 컴파일 중에 일부 추가 검사 및 변환 작업을 줄여 컴파일 속도를 향상시킬 수 있습니다. 이 경우 엄격 모드가 컴파일 시간에 미치는 영향은 그다지 눈에 띄지 않을 수 있지만 대규모 응용 프로그램의 경우 엄격 모드를 사용하면 전반적인 성능이 향상될 수 있습니다.

5. 빈번한 함수 호출과 종료를 피하세요

빈번한 함수 호출과 클로저 사용으로 인해 바이트코드 구문 분석 및 생성에 따른 오버헤드가 증가합니다.
빈번한 함수 호출 및 종료를 방지하여 V8의 컴파일 효율성을 향상시키기 위해 다음 측면을 고려할 수 있습니다.

  1. 함수 호출 줄이기: 루프 본문과 자주 실행되는 코드 블록에서 함수 호출을 피하세요. 자주 호출해야 하는 함수의 논리를 호출 사이트에 인라인하여 함수 호출의 오버헤드를 줄입니다.

  2. 클로저 생성 방지: 루프 본문 및 자주 실행되는 코드 블록에 익명 함수 또는 클로저 생성을 피하십시오. 클로저를 생성하면 추가 메모리 할당 및 가비지 수집 오버헤드가 발생하여 성능에 영향을 미칩니다.

다음은 빈번한 함수 호출과 클로저를 피함으로써 V8의 컴파일 효율성을 향상시키는 방법을 보여주는 실제 적용 사례입니다.

배열이 있고 arr그 안의 모든 요소를 ​​제곱해야 하며 제곱된 결과가 누적된다고 가정합니다. 기존 구현에서는 이를 수행하기 위해 map()함수와 함수를 사용할 수 있습니다.reduce()

const arr = [1, 2, 3, 4, 5];

const squaredSum = arr
  .map((n) => n * n)
  .reduce((sum, n) => sum + n, 0);

console.log(squaredSum);

위 코드에서는 map()reduce()함수가 자주 호출되며, map()함수에 클로저를 사용하므로 성능 저하가 발생합니다.

map()성능을 향상시키기 위해 sum 함수의 논리를 reduce()호출 사이트에 인라인 할 수 있으며 클로저를 피할 수 있습니다. 구체적인 방법은 다음과 같습니다.

const arr = [1, 2, 3, 4, 5];

let squaredSum = 0;
for (let i = 0; i < arr.length; i++) {
    
    
  const n = arr[i];
  squaredSum += n * n;
}

console.log(squaredSum);

위 코드에서는 sum 함수 for대신 루프를 사용했습니다 . 이러한 개선을 통해 빈번한 함수 호출 및 클로저 생성이 방지되고 V8의 컴파일 효율성이 향상됩니다.map()reduce()

위의 방법은 단순한 예일 뿐이며 실제 요구 사항과 적용 시나리오에 따라 구체적인 최적화 방법을 선택하고 적용해야 합니다. --trace-optV8 의 최적화를 분석하여 JavaScript 코드의 성능을 최적화하는 등 V8에서 제공하는 도구와 방법을 사용할 수도 있습니다 .

6. 충분한 유형 정보를 사용하십시오

V8은 런타임 시 유형 정보에 따라 동적으로 컴파일할 수 있는 JIT(Just-In-Time) 컴파일을 지원합니다. 함수 매개 변수 및 반환 값과 같은 위치에서는 일반 유형 대신 특정 유형을 사용하여 컴파일 효율성을 높일 수 있습니다.

V8에 대한 충분한 유형 정보를 제공함으로써 컴파일 효율성을 향상시킬 수 있습니다. 이는 V8이 JIT(Just-in-Time) 컴파일러 기반의 JavaScript 엔진이기 때문입니다. JIT(Just-in-Time) 컴파일러는 런타임 시 JavaScript 코드를 효율적인 기계어 코드로 컴파일합니다. 유형 정보는 V8이 보다 정확한 컴파일 결정을 내리고 생성된 기계어 코드를 최적화하는 데 도움이 됩니다.

실제 적용 사례는 TypedArray를 사용하여 수많은 수치 계산을 처리하는 것입니다. TypedArray는 고성능 수치 계산을 달성하기 위해 메모리의 이진 데이터를 직접 조작할 수 있는 JavaScript의 특수 배열 유형입니다.

합계, 평균 등과 같은 백만 개의 요소로 구성된 배열에 대해 일부 수치 연산을 수행해야 하는 애플리케이션이 있다고 가정합니다. TypedArray를 사용하여 이 배열의 유형을 정의하고 V8에 각 요소의 유형 정보를 알릴 수 있습니다.

TypedArray를 사용하는 샘플 코드는 다음과 같습니다.

// 创建一个包含一百万个元素的Float64Array
const array = new Float64Array(1000000);

// 填充数组
for (let i = 0; i < 1000000; i++) {
    
    
  array[i] = Math.random();
}

// 计算数组的总和
let sum = 0;
for (let i = 0; i < 1000000; i++) {
    
    
  sum += array[i];
}

console.log(sum);

이 예제에서는 배열의 유형을 정의하기 위해 Float64Array 유형을 사용하여 배열에 64비트 부동 소수점 숫자가 포함되어 있음을 V8에 알립니다. 유형 정보를 제공함으로써 V8은 컴파일 타임에 코드를 최적화하고 보다 효율적인 기계어 코드를 생성할 수 있습니다.

요약하자면, 변수 유형을 정의하기 위해 TypedArray와 같은 충분한 유형 정보를 사용함으로써 V8이 보다 정확한 컴파일 결정을 내리고 보다 효율적인 기계어 코드를 생성하는 데 도움이 될 수 있으므로 V8의 컴파일 효율성이 향상됩니다.

요약하면, V8 컴파일은 함수 크기 및 복잡성 최적화, 동적 기능 방지, eval() 및 with 문 방지, 엄격 모드 사용, 빈번한 함수 호출 및 클로저 방지, 충분한 유형 정보 효율성 사용을 통해 개선될 수 있습니다.

2. 객체 최적화

V8은 실행을 위해 JavaScript 코드를 기계어 코드로 컴파일하는 고성능 JavaScript 엔진입니다. V8에서는 객체를 추가, 삭제, 수정 및 쿼리하는 작업에는 객체 속성 액세스, 속성 삽입 또는 삭제, 속성 수정과 같은 작업이 포함됩니다.

V8은 히든 클래스(Hidden Class), 인라인 캐시(Inline Cache)와 같은 메커니즘을 사용하여 객체의 액세스 효율성을 향상시킵니다. 히든 클래스는 객체의 모양과 속성 레이아웃을 추적하는 데 사용되는 객체 속성 및 해당 값에 대한 컴파일 타임 바인딩 메커니즘입니다. 객체의 속성이 변경되면 히든클래스의 정보에 따라 히든클래스를 업데이트해야 하는지 판단하여 객체 속성의 수정 비용을 절감합니다. 인라인 캐싱은 속성의 액세스 경로를 캐시하는 데 사용되는 캐싱 메커니즘입니다. 인라인 캐싱을 통해 V8은 속성 액세스의 조회 비용을 줄이고 액세스 속도를 높일 수 있습니다.

V8의 컴파일 효율성을 향상시키기 위해 다음 사항을 따를 수 있습니다.

  1. 빈번한 속성 삽입 또는 삭제 방지: 객체 속성을 자주 수정하면 숨겨진 클래스가 변경되고 성능에 영향을 미칩니다. 속성을 자주 수정해야 하는 경우 배열과 같은 데이터 구조를 사용하거나 속성을 내부 변수로 캡슐화하는 것을 고려할 수 있습니다.

  2. 동적 속성 이름 사용 방지: 동적 속성 이름을 사용하면 V8에서 객체 액세스를 최적화하기가 어렵습니다. 동적 속성 이름이 필요한 경우 속성을 Map 객체에 저장하는 것이 좋습니다.

  3. 빈번한 속성 액세스 방지: 개체의 속성에 자주 액세스하는 것도 성능에 영향을 미칠 수 있습니다. 속성에 자주 액세스하는 경우 이를 로컬 변수에 저장하여 속성 조회 비용을 줄일 수 있습니다.

  4. 동일한 속성을 여러 번 수정하지 마십시오. 동일한 속성을 여러 번 수정하면 숨겨진 클래스가 여러 번 변경되고 성능에 영향을 미칩니다. 속성을 여러 번 수정해야 하는 경우 수정 작업을 하나의 수정으로 결합할 수 있습니다.

다음은 설명하기 위한 간단한 예입니다.

// 不推荐的写法
function updateObject(obj, prop, value) {
    
    
  if (!obj.hasOwnProperty(prop)) {
    
    
    obj[prop] = value;
  } else {
    
    
    obj[prop] += value;
  }
}

// 推荐的写法
function updateObject(obj, prop, value) {
    
    
  const oldValue = obj[prop] || 0;
  obj[prop] = oldValue + value;
}

권장하지 않는 작성 방법으로는 객체의 속성을 수정할 때마다 해당 속성이 존재하는지 먼저 확인한 후 해당 작업을 수행해야 하므로 속성에 자주 액세스하고 수정하게 됩니다. 권장되는 작성 방법에서는 먼저 속성 값을 로컬 변수에 저장한 다음 이를 수정하여 다중 속성 액세스 및 수정 비용을 피함으로써 V8의 컴파일 효율성을 향상시킵니다.

한마디로 V8의 컴파일 효율성은 객체의 속성을 합리적으로 조작하고 빈번한 속성 연산을 피함으로써 향상될 수 있다.

요약하다

프론트엔드 성능 최적화에서 자바스크립트 코드 최적화는 매우 중요한 부분입니다. 합리적인 코드 작성, 모듈식 개발, 비동기 로딩, 압축 및 캐싱은 페이지 응답 속도와 사용자 경험을 효과적으로 향상시킬 수 있습니다. JavaScript 파일 크기, 실행 시간, 페이지의 요청 수와 같은 지표에 주의를 기울이고 이를 타겟 방식으로 최적화해야 합니다. 동시에 코드 확장 및 유지 관리에 영향을 주지 않고 성능을 향상시키려면 사용자 경험과 코드 유지 관리 모두에 주의를 기울여야 합니다. 이 기사가 독자들이 JavaScript 최적화 방법을 더 잘 이해하고 적용하고 프런트 엔드 기술 수준을 향상시키는 데 도움이 되기를 바랍니다.

추천

출처blog.csdn.net/jieyucx/article/details/132489433