Computer >> 컴퓨터 >  >> 프로그램 작성 >> JavaScript

JavaScript로 고성능 "Get Viewport Dimensions" 미니 앱 구축

초보자 친화적이고 실용적인 바닐라 자바스크립트 튜토리얼. 중요한 시사점:고성능 창 이벤트 작성 방법 사용자의 하드웨어를 죽이지 않습니다.

대상:초보자부터 중급자까지

오늘 우리는 "Viewport Dimensions"라는 멋진 작은 앱을 만들고 있습니다. 이 기능은 한 가지 정말 잘합니다. 브라우저 창의 크기를 조정할 때 브라우저 뷰포트의 너비와 높이 값을 표시합니다.

이것은 반응형 디자인을 할 때 매우 중요한 도구입니다. CodePen에도 비슷한 기능이 있습니다. 하지만 더 큰 것과 몇 가지 추가 기능이 필요했기 때문에 직접 만들기로 결정했습니다. 그 과정에서 특히 성능 문제를 처리하는 방법에 대해 많은 것을 배웠습니다. 이제 여러분과 공유합니다!

표시 영역 크기

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

나는 당신의 기존 지식에 대해 가정하고 싶지 않습니다. 결과적으로 이것은 매우 상세한 튜토리얼.

기술 주제:

  • createElement()로 요소를 만드는 방법 방법.
  • Style object로 요소의 스타일을 지정하는 방법
  • 창 개체의 resize 설정 및 사용 방법 이벤트.
  • innerWidth를 사용하여 브라우저 뷰포트에서 너비와 높이를 가져오는 방법 및 innerHeight 속성.
  • 함수 외부에서 함수를 호출하는 방법(콜백).
  • 조건부(true/false)if 문이 작동합니다.
  • setTimeout()을 사용하여 타이머로 코드 실행을 지연시키는 방법
  • clearTimeout()으로 타이머를 재설정하는 방법 .
  • 이벤트 조절 기능 사용 방법 창 이벤트의 성능을 극적으로 향상시킵니다.
  • MS와 FPS의 관계 (밀리초 및 초당 프레임 수).
  • 인지된 성능의 중요한 차이점 및 하드웨어 성능

접근 방식

Viewport Dimensions 앱의 두 가지 버전을 구축 중입니다.

  • 버전 1 앱이 작동하도록 하는 것입니다. 초안이지만 최종 제품은 아닙니다.
  • 버전 2 버전 1을 개선하는 것입니다. 코드를 더 성능이 좋고 에너지 효율적이며 읽기 쉽게 만드는 방법을 알아보겠습니다.

JavaScript 중심을 유지하기 위해 우리는 모든 것을 할 것입니다. 자바스크립트 코드에서. 모든 것을 하나의 JavaScript 파일에 보관함으로써 우리 앱은 귀하의 기존 프로젝트에도 쉽게 추가할 수 있습니다.

완전한 초보자입니까? 그런 다음 CodePen을 사용하여 따라하는 것이 좋습니다. 사용하기 위해 가입할 필요도 없습니다. 여기에서 볼 수 있는 꽤 유명한 CodePen 비디오 자습서를 게시했습니다.

배우는 방법

혼란스러우면 몇 단락으로 돌아가서 중요한 것을 건너뛰지 않았는지 확인하십시오. 스스로 먼저 문제를 해결하려고 하면 더 많은 것을 배우게 될 것입니다. 그런 다음 두 번째 참조 코드를 찾습니다. .

길을 잃은 경우 완성된 코드를 항상 참조할 수 있습니다.

  • 버전 1
  • 버전 2

시작하겠습니다!

뷰포트 크기 [버전 1.0]

코딩을 시작하기 전에 프로젝트 요구 사항을 살펴보겠습니다.

요구사항

  • 창 너비와 높이를 표시하는 컨테이너가 있어야 합니다.
  • 창의 오른쪽 상단에 위치해야 합니다.
  • 기본적으로 숨겨져 있어야 합니다.
  • 창의 크기가 조정되는 즉시 표시되어야 합니다.
  • 최신 창 크기 조정 후 3초 후에 숨겨집니다.

이것이 버전 1의 기능 요구 사항의 핵심입니다.

코딩을 시작해 봅시다!

디스플레이 컨테이너 생성 및 스타일 지정

먼저 createElement를 사용하여 Viewport Dimensions 앱에 대한 div 요소를 생성해 보겠습니다. 메소드 및 변수에 할당:

var viewportDimensions = document.createElement("div");

이제 빈 <div></div>가 있습니다. 변수 내부에 저장된 요소.

브라우저에서 모든 HTML 요소는 요소 개체로 표시됩니다. 이러한 요소 개체에는 속성이 있습니다. 및 메서드 JavaScript로 액세스할 수 있습니다.

브라우저 창의 오른쪽 상단 모서리에 표시되는 뷰포트 너비와 높이를 원합니다. 이를 처리하고 HTML DOM Style 개체에 액세스하여 div 요소에 스타일을 지정하겠습니다. 속성:

viewportDimensions.style.position = "fixed";
viewportDimensions.style.right = "0";
viewportDimensions.style.top = "0";
viewportDimensions.style.padding = "16px";
viewportDimensions.style.zIndex = "3";
viewportDimensions.style.fontSize = "22px";

위의 구문은 점 표기법입니다. 간단히 말해서 . 개체의 속성 또는 메서드에 액세스합니다. 따라서 위의 예에서는 다음과 같이 말합니다.

  • 안녕하세요, viewportDimensions
  • Style Object에 대한 액세스 권한 부여
  • 스타일링 속성에 액세스할 수 있도록

Style 개체로 스타일을 지정하는 것은 CSS로 스타일을 지정하는 것과 같습니다. 그러나 Style 개체는 인라인 스타일을 사용합니다. 스타일 속성은 외부 CSS 스타일시트가 아닌 HTML 요소에 직접 추가됩니다.

Viewport Dimensions <div>를 추가하여 코드가 작동하는지 확인합시다. <body> 요소 HTML 문서의 요소입니다.

먼저 문서의 본문 요소에 대한 참조를 저장할 변수를 선언하겠습니다. 자바스크립트 파일 상단에 다음 코드를 추가하세요.

var body = document.querySelector("body");

이제 body 요소 안에 Viewport Dimension의 div 요소를 추가해 보겠습니다. JavaScript 파일의 맨 아래(마지막 스타일 아래:

body.appendChild(viewportDimensions);

appendChild() 메소드입니다. 다른 노드 내부에 노드를 추가(추가)합니다. 모든 것 DOM에는 노드가 있으며 다양한 유형의 노드가 있습니다. 이 경우 body 요소 노드 내부에 div 요소 노드를 추가합니다.

div 요소에 아직 내용이 없기 때문에 현재 코드가 작동하는지 확인할 수 없습니다. 요소에 임시 테두리를 추가하여 빠르게 찾을 수 있습니다.

viewportDimensions.style.border = "10px solid";

작동하면 창의 오른쪽 상단 모서리에 두꺼운 검은색 테두리가 있는 작은 상자가 표시됩니다.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

브라우저 창에서 마우스 오른쪽 버튼을 클릭하여 확인할 수도 있습니다. 그런 다음 검사를 클릭합니다. 브라우저 DevTools에 액세스합니다.

이제 요소 탭에서 body을 찾습니다. 요소가 있고 일부 인라인 스타일 속성이 있는 빈 div 요소가 표시되어야 합니다.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축 DevTools에서 보이지 않는 div 위로 마우스를 이동하면 오른쪽 상단 모서리에 표시되지 않는 div가 강조 표시됩니다.

지금까지의 모든 코드에 대한 개요는 다음과 같습니다.

// Select body element
var body = document.querySelector("body");

// Create div element
var viewportDimensions = document.createElement("div");

// Style element
viewportDimensions.style.position = "fixed";
viewportDimensions.style.right = "0";
viewportDimensions.style.top = "0";
viewportDimensions.style.padding = "16px";
viewportDimensions.style.zIndex = "3";
viewportDimensions.style.fontSize = "22px";

// Add div element inside body element
body.appendChild(viewportDimensions);

좋습니다. div 요소가 생성되고, 스타일이 지정되고, body 요소 내부에 추가되었습니다. 다음은 창 크기 조정 이벤트입니다.

창 크기 조정 이벤트 설정

Window 개체는 브라우저 창을 나타냅니다. addEventListener를 포함한 여러 메서드가 있습니다. . 이 방법은 많은 유형을 수신할 수 있습니다. 스크롤, 클릭, 타이핑 및 크기 조정과 같은 창 이벤트.

'resize'을 사용하겠습니다. 이벤트. body.appendChild 아래 다음을 추가하십시오:

window.addEventListener("resize", function() {
  // Code to execute when window resizes
});

참고:주석 // 브라우저에서 해석되지 않고 우리 인간만을 위한 것입니다.

이전에 점 표기법을 사용하여 div 요소의 속성을 가져왔습니다. 이제 이를 사용하여 메서드에 액세스합니다. 창 개체:addEventListener .

두 개의 인수를 전달하고 있습니다. 이벤트 리스너:'resize'function() . 크기 조정 이벤트에 대해 이미 논의했지만 그 기능은 무엇입니까?

function() 창 크기 조정 이벤트가 활성화될 때마다(창 크기를 조정하는 즉시) 실행할 코드 블록을 설정합니다. 코드 블록은 중괄호 { } 안에 있는 것입니다. (함수 본문이라고도 함) 지금까지는 // comment 만 있습니다. .

창 이벤트를 호출할 때마다 function() 중괄호 { } 안의 코드를 실행하려면 .

작동하는지 확인하기 위해 console.log()를 사용하여 테스트해 보겠습니다. :

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  console.log("Working!");
});

이제 창 크기를 조정합니다. 콘솔이 'Working!'을 인쇄하는 경우 여러 번, 이는 창 크기 조정 이벤트가 작동 중임을 의미합니다.

콘솔 액세스

CodePen에서 콘솔에 액세스하려면 창의 왼쪽 하단 모서리에 있는 콘솔 버튼을 클릭합니다. Chrome에서 콘솔에 액세스하려면 다음 단축키를 사용하세요.

  • Cmd + Opt + J(Mac).
  • Ctrl + Shift + J(Windows/Linux)

자, Window Event를 작동시키도록 합시다!

브라우저 너비 및 높이를 픽셀 단위로 반환

다음 이동은 뷰포트 너비와 높이의 숫자 값을 잡는 것입니다. 창의 크기를 조정할 때 값이 즉시 업데이트되기를 원합니다. 창 개체 브라우저 창을 나타냅니다. innerWidth라는 멋진 속성이 몇 개 있습니다. 및 innerHeight .

그들이 무엇을 하는지 맞춰보세요?

네, 브라우저 창의 너비와 높이를 픽셀 단위로 반환합니다(스크롤바 포함). 이를 확인하고 console.log()를 사용합시다. 너비 및 높이 속성 값을 반환합니다.

현재 값을 동적으로 가져오기를 원하기 때문에 console.log()를 넣어야 합니다. 크기 조정 이벤트의 함수 블록 내부:

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  console.log("Width:", window.innerWidth);
  console.log("Height:", window.innerHeight);
});

'Width:''Height:' console.log()의 텍스트 는 콘솔 출력을 명확하게 하기 위한 것입니다.

실제로 window.를 작성할 필요가 없습니다. 너비 및 높이 값을 가져오려면 innerWidthinnerHeight 작동합니다. 혼란을 피하기 위해 그렇게 합니다.

작동하면 브라우저 창의 크기를 조정하는 한 콘솔은 현재 표시 영역의 크기를 계속해서 인쇄합니다.

다음과 같아야 합니다.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

이제 우리는 어딘가로 가고 있습니다!

console.log()를 없애자 대신 너비 및 높이 속성을 자체 변수에 할당하여 참조를 저장할 수 있습니다.

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  var width = window.innerWidth;
  var height = window.innerHeight;
});

이제 widthheight 항상 창 너비 및 높이 속성의 현재 값을 포함합니다. 항상 반환된 값을 변수에 할당해야 하지만 나중에 해당 정보를 사용하거나 변경할 수 있으므로 좋은 습관입니다.

새 변수가 제대로 작동하는지 확인하려면 새 변수를 콘솔에 인쇄해 보십시오.

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  var width = window.innerWidth;
  var height = window.innerHeight;

  console.log(width);
  console.log(height);
});

모든 것이 작동하면 console.log를 제거하고 계속 진행할 수 있습니다.

div 요소에 너비 및 높이 값 추가

반환된 너비와 높이 값을 div 요소에 추가하려고 합니다. 보다 구체적으로 우리는 값을 내부 div 요소 열기 및 닫기 태그:

&lt;div&gt; We want width &amp; height values here &lt;/div&gt;

그렇게 하려면 div 요소를 저장하는 변수를 가져와야 합니다. viewportDimensions . 그런 다음 textContent라는 요소 개체의 속성에 액세스해야 합니다. . 이전과 동일한 점 표기법을 사용합니다.

viewportDimensions.textContent;

이제 너비와 높이 변수를 할당하기만 하면 됩니다.

viewportDimensions.textContent = width + "px" + " x " + height + "px";

지금 브라우저 창의 크기를 조정해 보십시오. 모든 작업을 올바르게 수행했다면 창의 오른쪽 상단 모서리에 현재 너비와 높이 값이 표시되어야 합니다.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

위에서 사용한 코드 구문이 약간 혼란스러워 보일 수 있다는 것을 알고 있습니다.

분해해 봅시다:

textContent 요소 개체의 속성입니다. Viewport Dimensions div 요소를 포함하여 문서의 모든 요소에는 이 요소가 있습니다.

textContent 노드를 반환합니다. 특히 텍스트 노드 . 예:단락 요소 안의 텍스트:<p>Some text...</p> , 텍스트 노드입니다.

viewportDimensions 변수에 빈 <div>가 있습니다. 요소. 이제 여는 div 요소 태그와 닫는 div 요소 태그 사이에 숫자 픽셀 값이 있는 텍스트 노드를 반환합니다.

width + "px" + " x " + height + "px";

widthheight 둘 다 픽셀 번호 값을 포함합니다. 'px'만 추가합니다. 및 ' x ' (문자열) 너비와 높이 변수를 구분하고 반환하는 값이 픽셀 단위라는 것을 모든 사람에게 명확하게 하기 위해.

setTimeout()으로 카운트다운 타이머 추가

창의 크기를 조정하지 않을 때 너비와 높이가 일정하게 표시되는 것을 원하지 않습니다. 브라우저 창 크기 조정을 중지한 후 정확히 3초 후에 Viewport Dimensions의 div 요소가 사라지도록 합시다.

그렇게 하려면 창 개체의 다른 방법을 사용해야 합니다. , setTimeout이라고 함 . 이 메소드는 function()을 실행하도록 설계되었습니다. 한 번 지정된 밀리초 수.

다음과 같이 작동합니다.

setTimeout(functionToExecute, 3000);

1000ms =1초. 따라서 위의 3000은 3초를 의미합니다.

어떤 기능을 실행하고 싶습니까? Viewport Dimensions의 div 요소를 제거하는 것입니다.

아직 그런 함수가 없습니다. 하나 만들고 removeViewportDimensions()라고 부르겠습니다. 코드 블록 { } 내부 div 요소를 제거하도록 합시다.

위에 다음 코드를 추가하세요. 창 이벤트 기능:

function removeViewportDimensions() {
  viewportDimensions.style.display = "none";
}

display 속성은 방법 또는 if를 지정합니다. 요소가 표시됩니다. 'none'으로 설정하여 , 우리는 그것을 숨기고 있습니다.

이제 전화해야 합니다. 새로운 removeViewportDimensions() 기능, 내부 우리의 창 이벤트 코드 블록. setTimeout() 사용 이전 형식에서 다음을 추가합니다.

setTimeout(removeViewportDimensions, 3000);

이제 창 크기 조정 이벤트가 활성화될 때마다 setTimeout 3초의 카운트다운을 설정합니다. 즉, 우리는 지연합니다. removeViewportDimensions() 호출 3초.

3초가 지나면 removeViewportDimensions() 함수가 호출되고 해당 코드를 실행합니다.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

이제 div 요소의 display 속성이 'none'으로 설정되었습니다. , 및 숨겨져 있습니다.

하지만 문제가 있습니다

div 요소가 제거된 직후 브라우저 창의 크기를 다시 조정하려고 하면 div 요소가 다시 표시되지 않습니다. 마지막이기 때문입니다. 우리 프로그램에서 일어나는 일은 div 요소가 display 속성이 'none'으로 설정됨 .

div 요소가 다시 표시되기를 원한다고 명시한 프로그램은 어디에도 없습니다.

그런데 왜 처음에 표시되었을까요? 기본적으로 <div> 요소는 소위 블록 수준입니다. 요소. 즉, 기본 display 속성 값은 'block'입니다. — 보이는 디스플레이 유형.

div 요소에 대한 가장 마지막 작업은 표시 값을 'none'으로 설정하는 것입니다. . 따라서 해당 값은 여전히 두 번째로 크기 조정 이벤트를 실행할 때 요소에 있어야 합니다. 페이지를 새로고침하지 않는 한

이것은 쉽게 고칠 수 있습니다. 창 크기 조정 이벤트의 코드 블록 내부에 다음을 추가합니다(setTimeout !):

viewportDimensions.style.display = "block";

이제 div 요소의 display 속성이 'block'으로 설정되었습니다. 크기 조정 이벤트가 실행될 때마다 창의 크기를 조정하고 div 요소가 숨겨질 때까지 기다렸다가 다시 크기를 조정하세요.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

훌륭합니다. 우리 앱이 작동합니다!

음.. 일종의. 또 다른 문제가 있습니다. 장기간(3초 이상) 브라우저 창의 크기를 조정하려고 하면 div 요소가 깜박이기 시작합니다. 계속해서 켜지고 꺼지는 조명과 같습니다.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축 우리 앱이 얼마나 가치가 없는지!

카운트다운 타이머를 재설정하지 않기 때문에 발생합니다. 뷰포트의 크기를 조정할 때마다 창 이벤트는 기능 코드 블록을 최대한 많이 실행합니다. 따라서 removeViewportDimensions() 기능은 또한 여러 번 호출됩니다.

이로 인해 앱에 중복되는 코드 실행이 많이 발생합니다. div 요소가 display = 'none'으로 망치질 중입니다. 속성 display = 'block' 동시에 속성.

이렇게 하면 div 요소가 지속적으로 표시되고 숨겨지고 깜박임이 발생합니다. 짜증난다. 이 문제를 해결하려면 타이머를 지우는 방법을 배워야 합니다. 자바스크립트에서 작동합니다.

카운트다운 타이머 재설정

clearTimeout()을 사용하여 기존 타이머를 지울 수 있습니다. 방법. 이 방법은 삭제하도록 설계되었습니다. setTimeout으로 설정된 타이머 방법. 파트너 방법과 같습니다.

기존 타이머를 지우는 것이 바로 우리가 원하는 것입니다. setTimeout()만 실행하고 싶습니다. 타이머 한 번 크기 조정 이벤트당.

clearTimeout()을 실행할 수 있다고 생각할 수도 있습니다. setTimeout()에서 이렇게:

clearTimeout(setTimeout);

하지만 작동하지 않습니다. clearTimeout() 메서드를 사용하려면 global 타임아웃 메소드 생성 시 변수

JavaScript에는 전역 및 로컬의 두 가지 범위가 있습니다.

  • 전역 변수 함수 외부(전역 범위)에서 선언된 변수입니다.
  • 로컬 변수 함수 내에서 선언된 변수입니다(로컬 범위).

즉, setTimeout()을 지우려면 먼저 전역 변수에 할당하고 그 다음 clearTimeout()을 호출할 수 있습니다. 해당 변수에 대해 재설정합니다.

전역 변수를 만들고 resizeTimeout이라고 부르겠습니다. :

var resizeTimeout;

이 변수를 JavaScript 파일의 맨 위에 두십시오.

지금은 그냥 빈 변수입니다. 크기 조정 이벤트가 처음 시작될 때까지만 비어 있습니다.

console.log(resizeTimeout)를 사용하려고 하면 정의되지 않음이 됩니다. 돌아왔다. undefined 거짓입니다. 중요한 가치 유형입니다. 그 이유를 곧 알게 될 것입니다.

이제 setTimeout() 이전의 함수를 resizeTimeout에 할당합니다. 변수:

resizeTimeout = setTimeout(removeViewportDimensions, 3000);

이제 전역 resizeTimeout 변수는 setTimeout에 대한 정보를 받습니다. 크기 조정 이벤트가 활성화되는 즉시 기능.

이제 setTimeout()을 사용할 수 있습니다. 창 크기 조정 이벤트가 실행될 때마다. clearTimeout() 설정 전역 resizeTimeout에서 변하기 쉬운. 이렇게:

clearTimeout(resizeTimeout);

resizeTimeout = setTimeout() 바로 위에 코드를 넣습니다. 그래서 다음과 같이 보입니다:

clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(removeViewportDimensions, 3000);

자, 이제 5-6초 동안 크기 조정 이벤트를 실행하면 깜박임이 사라진 것을 볼 수 있습니다!

혼란스럽습니까? 코드에서 어떤 일이 일어나는지 이야기해 봅시다.

JavaScript 인터프리터(브라우저에서 실행되는 엔진)는 코드를 읽고 다음을 수행합니다.

  • 한 줄씩 실행
  • 한 번에 한 줄
  • 위에서 아래로

창의 크기를 계속 조정하는 한 코드는 위에서 아래로 계속 실행됩니다. 모든 작은 크기 조정은 새 창 이벤트를 발생시킵니다. 따라서 JavaScript 인터프리터는 초당 여러 번 코드를 읽고 실행합니다.

창 이벤트의 함수가 코드 블록을 실행할 때마다 clearTimeout() 모든 기존을 재설정합니다. 대기열의 카운트다운, resizeTimeout 변수.

마지막 코드 줄에서 setTimeout()을 할당합니다. .

따라서 마지막으로 발생하는 일은 항상 하나가 됩니다. resizeTimeout에 할당되는 3초의 카운트다운 . 그 전에 시작된 카운트다운은 clearTimeout()에 의해 지워집니다. .

엄청난! 버전 1이 완료되었습니다. 여기에서 전체 코드를 볼 수 있습니다. 버전 2로 넘어가겠습니다. 여기서는 성능에 특히 중점을 둡니다.

<시간>

표시 영역 크기[버전 2]

우리 앱은 작동하지만 충분합니까? 이 질문에 답하려면 두 가지 중요한 사항을 고려해야 합니다.

  • 인지된 성능:사용자 경험(UX).
  • 하드웨어 성능(사용 및 효율성).

UX의 관점에서 우리 앱의 성능은 훌륭하다고 생각합니다. 그것은 놀랍도록 빠른 응답 시간을 가지고 있으며 오래된 화면에서도 매우 잘 렌더링됩니다. 우리는 항상 비주얼 최적화(UI 디자인)에 대해 논쟁할 수 있습니다. 그러나 순수한 기능을 기반으로 하는 우리 앱은 잘 작동합니다.

그러나 하드웨어 성능에서 관점에서 볼 때 우리 앱은 정말 나쁜. 우리 앱은 기술 ​​요구 사항이 얼마나 적은지에 비해 엄청난 CPU 및 GPU 리소스를 사용하고 있습니다.

이유를 알 수 있습니까? 식욕적인 성격에 익숙하지 않을 때 본능적으로 생각하는 것이 아닙니다. 창 이벤트.

문제는 다음과 같습니다.

브라우저 창의 크기를 조정할 때마다 앱의 창 이벤트는 수백 번 기능을 실행합니다. 몇 초 만에!

문제를 시각화하는 함수를 CodePen에 올렸습니다. 초당 얼마나 많은 기능이 실행되는지 확인하십시오. 또한 빠르게 지붕을 뚫고 총 카운트가 날아가는 것을 지켜보십시오.

코드펜 예시

이것은 끔찍하고 완전히 불필요합니다! 코드가 예상보다 훨씬 많은 리소스를 사용하고 있습니다.

브라우저 이벤트 동안 CPU와 GPU가 얼마나 작동하는지 확인하려면 Chrome의 작업 관리자를 실행하세요.

JavaScript로 고성능  Get Viewport Dimensions  미니 앱 구축

브라우저 창의 크기를 조정해 보십시오. 작업 관리자 내에서 활성 브라우저 탭 옆에 CPU 및 GPU 사용량 %가 반환됩니다.

절대적인 하드웨어 사용량과 상대적인 하드웨어 사용량

절대적인 하드웨어 사용량과 상대적인 하드웨어 사용량을 구별하는 것이 중요합니다. 절대적인(총) 하드웨어 사용 관점에서 볼 때 우리의 작은 앱은 큰 해를 끼치지 않습니다. 대부분의 컴퓨터는 이것에 흔들리기에는 너무 강력합니다.

그러나 친척으로부터 사용 관점에서 볼 때 우리 앱은 끔찍하게 비효율적입니다. 그리고 그것이 문제입니다. 우리는 성능을 소홀히 하는 습관을 들이고 싶지 않습니다. 그것은 우리를 괴롭히고 다시 와서 우리를 물어뜯을 것이기 때문입니다.

무거운 실행 애플리케이션으로 작업을 시작하자마자 기능, 하드웨어 사용이 심각한 문제가 됩니다. 지금처럼 코드를 실행하면 보기가 좋지 않을 것입니다.

창 이벤트 실행 방법

기본적으로 표준 창 이벤트는 이벤트가 활성화되어 있는 한 가능한 한 여러 번 기능을 실행합니다. 모든 작은 변경은 새 창 이벤트를 트리거합니다. 이것이 우리 앱이 현재 엄청나게 높은 실행률을 보이는 원인입니다.

함수는 초당 몇 번 실행되나요?

4에서 40밀리초마다 무엇이든 될 수 있습니다. 다음을 포함한 많은 요인에 따라 다릅니다.

  • 당신의 CPU와 GPU(하드웨어)는 얼마나 강력합니까?
  • 어떤 브라우저를 사용하고 있습니까?
  • 실행 중인 소프트웨어(코드)가 얼마나 복잡합니까? 애니메이션이 포함되나요?
  • 현재 귀하의 하드웨어는 무엇을 하고 있습니까? 다른 탭에서 실행 중인 YouTube 동영상이 있습니까?

하드웨어는 사용자가 작업을 수행하도록 요청한 주어진 시간에 사용할 수 있는 모든 리소스를 사용합니다.

때때로 무료가 충분하지 않습니다. 수많은 앱이 동시에 실행되고 있기 때문에 리소스를 사용하여 요청에 즉시 응답할 수 있습니다.

이로 인해 느린 응답 시간, 화면 결함, 정지 및 기타 문제가 발생할 수 있습니다.

하드웨어 사용량이 늘어납니다. 이것이 애플리케이션의 현재 상태를 수정해야 하는 이유입니다. 우리는 성능을 중요시하기 때문입니다!

참고:최신 브라우저에서 최소 실행 속도는 4ms입니다. 프레임 속도 측면에서 약 250fps입니다. 이것은 Mozilla의 Web API 문서에 따릅니다.

하지만 이 주제에 대해 상충되는 정보가 있습니다. 자세한 정보는 여기를 참조하세요.

<블록 인용>

함수를 얼마나 자주 "실행해야"합니까?

이상적인 함수 실행 속도는 컨텍스트에 따라 다릅니다. 우리는 상세한 애니메이션으로 작업하고 있습니까? 아니면 몇 개의 숫자 값을 반환하는 것과 같은 간단한 작업(예:앱에서 하는 것과 같이)이 무엇입니까?

컨텍스트에 관계없이 일반적으로 창 이벤트가 가능한 한 많은 기능을 실행하는 것을 원하지 않습니다. 말도 안되는 소리야. 또한 무료가 아닙니다. 막아야 합니다!

조절이라는 프로세스를 사용하여 실행 빈도를 제어할 수 있습니다. 다음 내용입니다.

구조를 위한 이벤트 조절 기능!

조절 기능을 사용할 수 있습니다. 다른 횟수를 제한하기 위해 함수는 시간이 지남에 따라 실행됩니다. 예:"이 함수는 100ms당 한 번만 호출하십시오."

창 크기 조정 이벤트에 의해 트리거되는 기본 이벤트 조절기 기능을 살펴보겠습니다. 그러면 스로틀러가 100ms마다 외부 함수를 호출합니다.

기본 조절기 기능:

var throttled;
var delay = 100;

function functionToExecute() {
  console.log("Executed!");
}

function throttler() {
  if (!throttled) {
    functionToExecute();
    throttled = true;
    setTimeout(function() {
      throttled = false;
    }, delay);
  }
}

window.addEventListener("resize", throttler);

읽기 쉽도록 코드 서식에 공백을 추가했습니다. 코드를 몇 번 읽고 이해했는지 확인하세요.

이 CodePen을 사용하여 테스트하십시오. functionToExecute()를 호출하는 것을 볼 수 있습니다. 초당 최대 10회(10 x 100 =1000ms =1초).

저는 최대라고 말합니다. 함수가 항상 설정한 속도로 정확하게 실행되지는 않기 때문입니다. 기능이 실행되는 시간에 하드웨어가 얼마나 바쁜지에 따라 다릅니다. 컴퓨터에서 다른 에너지 과세 앱을 실행하고 있습니까?

스로틀러 코드에서 일어나는 일:

처음 이해하지 못하더라도 걱정하지 마십시오. 마침내 클릭할 때까지 이 항목을 어지럽히는 데 많은 시간을 보냈습니다.

JavaScript 파일의 맨 위에서 두 개의 global 변수:

var throttled; // Empty variable. Type: undefined (falsy value)

var delay = 100; // Number

참고:전역 변수는 어디에서나 이러한 변수에 액세스할 수 있음을 의미합니다.

throttled을 사용합니다. throttler()에 대한 참조점으로 함수, 대기열에 함수가 있는지 확인합니다.

throttler() 전에 함수가 처음으로(크기 조정 이벤트에 의해) 트리거되면 대기열에서 실행할 함수가 없습니다. 그래서 throttled 빈 변수로 시작합니다.

기본적으로 빈 변수의 값 유형은 undefined입니다. — 이는 거짓입니다. 값 유형. 이것이 왜 중요한지 곧 알게 될 것입니다.

그런 다음 delay라는 변수에 숫자 값(100)을 할당합니다. . ms(밀리초)를 조절하는 데 사용하는 값입니다. throttler()의 실행 속도 기능.

delay에 100ms를 할당합니다. 변하기 쉬운. 그런 다음 해당 변수를 조절기의 setTimeout()에 전달합니다. . 그러면 스로틀러가 100ms마다 또는 최대 10초에 10번 실행됩니다.

저는 최대라고 말합니다. 100ms는 실행 속도에 상한선을 두기 때문입니다. 사용자의 하드웨어와 소프트웨어에 따라 실제로 초당 10개 미만의 함수 호출을 받을 수 있습니다. 그러나 대부분의 컴퓨터는 초당 10번 실행할 수 있습니다.

throttler 함수 내에서 조건부 if를 설정합니다. 성명:

function throttler() {
  if (!throttled) {
    // code to execute
  }
}

조건문은 지정된 조건에 참 값이 있는지 확인합니다.

! 기호는 not을 의미합니다. . 따라서 if (!throttled) 번역:

"조절되지 않으면 않습니다 진실한 값이 있으면 if 실행 의 코드'입니다.

"하지만 throttled 하지 진실한 가치를 가지고 있다면 바로 거기에서 멈춰라!”

자바스크립트에서 True 및 False 값이란 무엇입니까?

자바스크립트에는 진실이 있습니다. 및 거짓 가치. 네, 그렇게 부릅니다. 진실은 진실한 가치입니다. Falsy는 거짓으로 간주되는 값입니다(놀랍습니다!).

JavaScript에는 6개의 잘못된 값이 있습니다.

  • undefined
  • null
  • 0
  • '' (빈 문자열)
  • NaN
  • false

JavaScript에서 아닌 모든 것은 one of the above values is considered a truthy value. That’s pretty simple, right?

Back to the throttler

With that quick lesson on true vs. false, go ahead and check if our throttled variable is indeed undefined, and a falsy value type.

We can quickly find out with console.log() by using !! to check our variable:

var throttled;
console.log(throttled); // undefined
console.log(!!throttled); // false value

!! is a double not operation. It’s a quick way to check for truthy and falsy values.

Great, now we have confirmed that throttled is undefined, and a falsy value type. This means that the very first time our throttler() runs, if ’s condition is indeed met.

// I start out as a falsy value
var throttled;

// I’m triggered by the window resize event
function throttler() {
  // I will only run my { code } if throttled is falsy (it is!)
  if (!throttled) {
    // code to execute
  }
}

Which means that we can move onto what happens inside if’s code block.

Inside if’s code block

Once inside the if statement code block, we immediately start the callback to functionToExecute .

We also set our global throttled variable to true, so it’s no longer undefined (no longer a false value). This stops any future calls to functionToExecute() .

if (!throttled) {
  // Run callback
  functionToExecute();
  // Set global throttled variable to true
  throttled = true;

  // ...
}

But then right below, we use setTimeout to reset the the throttled value back to a falsy value, after the 100ms delay:

function throttler() {
  if (!throttled) {
    // Run callback
    functionToExecute();
    // Set global throttled variable to true
    throttled = true;

    setTimeout(function() {
      // Set throttled back to false after delay
      throttled = false;
    }, delay);
  }
}

So every time the window resize event is running, it triggers the throttler() , which will call functionToExecute every 100ms!

Throttling is power

It’s easier to understand how powerful throttling is if you look at two opposite extremes. Try the following in the throttler function on CodePen:

  • Swap 100 out with 500 and resize your window. Notice how infrequent the functionToExecute() is called (twice per second).
  • Then try to swap out 500 with 16 and resize the window. Now functionToExecute() is bombarded with calls (up to 60 calls per second).

That’s how throttling works. We use it to limit the number of times a function can be called over time. It’s a very easy way to avoid wasting hardware resources. The hard part is finding the “optimal” execution rate for a given function, as no project is the same. More about that later.

Adding the throttler to our project

To apply the throttler function to our own project, we’ll need to do a bit of refactoring to the old code first. Refactoring is when we improve the structure of a program but don’t change the overall functionality.

In other words:we take something that already works, and makes it easier to use and understand.

We no longer want the window resize event to directly execute the function that returns width and height. Instead, we want our throttler function to regulate when and how often the code executes.

Fortunately, the change is simple. We just need to declare a named function and then put all code from the anonymous function inside that named function.

Let’s call the new function getViewportDimensions() :

function getViewportDimensions() {
  var width = window.innerWidth;
  var height = window.innerHeight;

  viewportDimensions.textContent = width + "px" + " x " + height + "px";
  viewportDimensions.style.display = "block";

  clearTimeout(resizeTimeout);
  resizeTimeout = setTimeout(removeViewportDimensions, 3000);
}

Now let’s take the same throttler function from earlier, and replace the functionToExecute() with getViewportDimensions() :

function throttler() {
  if (!throttled) {
    // Callback: the function we want to throttle
    getViewportDimensions();

    throttled = true;

    setTimeout(function() {
      throttled = false;
    }, delay);
  }
}

And finally we add the window resize event listener:

window.addEventListener("resize", throttler);

That’s it, all the hard work is done! Before we wrap up, let’s check our app’s performance, and see if we need to tweak anything.

Hardware Performance vs. Perceived Performance

I don’t know about you, but when I resize my browser window, the width and height numbers are rendering a bit laggy to my screen. It’s not as smooth as it was before we added the throttler.

But that’s not surprising. Before we added the throttler, our code’s execution rate was absurdly high. Now it’s firing around 10 times per second. That’s why it’s a bit laggy now.

There’s no doubt that our app is very performant, from a hardware usage perspective. Our hardware hardly does any work, so it absolutely loves us right now. Which is good.

But what about the perceived performance, from the User Experience point of view? Do our users love us too?

Our rendering should be smoother. Our function execution rate is currently capped at 10 times per second. Let’s increase it. But how much?

We can make it easier to make that decision if we first take a look at the relationship between time and frame rate.

Time vs. Frame Rate

Frame rate is also known as FPS (Frames Per Second). It refers to the number of individual frames displayed per second.

In general, the higher fps the smoother the rendering will be. Video games often need 60fps or more to render smoothly. Most movies and tv series run smoothly at 24-30fps. The more fast-paced action a video or graphic has, the more FPS it needs to render smooth.

For some types of graphics, you can go as low as 15fps and still get a smooth render. But you should rarely go below 15fps because then the perceived performance will start to look noticeably slower.

To find your desired FPS in ms, you divide your target fps with 1000, e.g. 1000/15(fps) =66ms.

Take a look at this FPS to millisecond table:

var 2fps  = 1000/2; // 500ms
var 10fps = 1000/10; // 100ms
var 15fps = 1000/15; // 66ms
var 24fps = 1000/24; // 42ms
var 30fps = 1000/30; // 33ms
var 60fps = 1000/60; // 16ms

Do you recognize something? Our app is currently executing every 100ms, or in frame rate terms:10 frames per second.

Remember, I just said that anything below 15fps will usually appear slow? That could explain why current app’s rendering feels a bit off. There are not enough frames per second to render it smooth. It doesn’t feel instant.

Let’s do some testing

I’ll guarantee that if we crank our Viewport Dimensions feature up to run at 15fps (66ms), it will look significantly smoother than at the current 10fps (100ms).

And it won’t cost too much extra CPU power.

We only need it to be smooth enough.

Like I said earlier, testing opposite extremes is a good way to find out what not to do. Then the question becomes where between the two extremes does your project fit?

Try testing the following frame rates:5fps (500ms), 15fps (66ms), and 60fps (16ms) on your Viewport Dimensions app and see what happens.

What do you think?

5fps looks horrible. It looks broken. That would never work. Our hardware would love it, but our users will hate it!

15fps looks good to me. I wouldn't say that this frame rate is 100% smooth, but it’s clearly better than 10fps.

It’s also important to remember that if your eyes are trained to look for small details, it’s not comparable to the average user’s experience. Most people will consider 15fps smooth, for this type of graphic.

60fps is super smooth — not surprisingly. But honestly, it’s not worth massively extra hardware usage.

I’m going to settle at 15fps for my app.

Why 15 FPS?

The reason I decided on 15fps / 66ms, is because that frame rate is high enough to be perceived as smooth (for most people).

Most software, computers, and displays (screens) can render at 15fps without problems. Even most small, handheld devices can handle 15fps without issue.

The irony of high frame rates is that while logic tells us that more frames per second =smoother, it can also have the opposite effect.

If you try to force a frame rate or refresh rate that your user’s hardware and software can’t handle, the result is often:lagging.

Refresh rate :is how many times your display can redraw your screen. A refresh rate of 45Hz means that your display can redraw it’s entire screen 45 times in 1 second.

Now if your CPU &GPU can generate a frame rate of 60fps, but your display’s refresh rate is only 45Hz, then you have a mismatch. This often causes unpredictable results.

We developers and designers can easily get out of touch with reality. Our development machines are usually more powerful than the average person’s computer.

This is why we need to do solid research and test our assumptions before we push products on the market.

So 15fps is a happy medium that will also work for people who don’t have powerful machines.

Using 15fps will also save us at least 75% of the energy our hardware used before we added the throttler.

Anything below 15fps will usually start to look slow and laggy. It becomes really obvious once you get to around 10fps, which is why our initial frame rate wasn’t good enough.

Here’s an insightful video on the topic of response times which supports my argument for not going below 15fps (on most things).

Context &the Minimum Effective Dose

How much of a perceived difference is there from 15 to 30fps? If you test it out on the app we just built, you’ll be surprised.

You probably won’t be to notice any significant difference. Not a deal-breaking difference. But the price you pay for hardware usage is double up!

High fps costs a lot of hardware power. So why use more than necessary? There’s always a point of diminishing returns. That’s where the Minimum Effective Dose (MED) comes in. You only need enough, to get the desired effect, no more, no less.

Of course, it always depends on the context. Are we talking about an explosive first-person shooter video game or a simple pixel counter like the one we’ve built? Context is key!

A Finishing Touch

All the hard work is done. For good measure, let’s wrap all our code inside an IIFE ((function () {...})(); ) and initialize use strict mode inside:

(function() {
  "use strict";

  // Put all your code below

})();

IIFE (Immediately-Invoked Function Expression), keeps all your code inside a local scope.

If we don’t wrap our code like this, we risk “polluting the global namespace”. This is a fancy way of saying that we risk causing conflicts with other code, outside of our app.

use strict; is also used to prevent conflicts with 3rd party software that don’t follow strict coding rules.

We’re done!

Here is all the code we’ve written. I've added some comments for clarification and some extra white space for readability:

Finished project code:

(function() {
  "use strict";

  // throttled value before window event starts
  var throttled;

  // Delay function calls to 66ms (frame rate: 15fps)
  var delay = 66;

  // Declare empty variable for later use
  var resizeTimeout;

  // Grab body element
  var body = document.querySelector("body");

  // Create element
  var viewportDimensions = document.createElement("div");

  // Style element
  viewportDimensions.style.position = "fixed";
  viewportDimensions.style.right = 0;
  viewportDimensions.style.top = 0;
  viewportDimensions.style.padding = "16px";
  viewportDimensions.style.zIndex = 3;
  viewportDimensions.style.fontSize = "22px";

  // Add div element inside body element
  body.appendChild(viewportDimensions);

  // window.resize callback function
  function getViewportDimensions() {
    var width = window.innerWidth;
    var height = window.innerHeight;

    viewportDimensions.textContent = width + "px" + " x " + height + "px";
    viewportDimensions.style.display = "block";

    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(removeViewportDimensions, 3000);
  }

  // Called from getViewportDimensions()
  function removeViewportDimensions() {
    viewportDimensions.style.display = "none";
  }

  function throttler() {
    // Only run code if’s block if we’re not throttled
    if (!throttled) {
      // Callback: the function we want to throttle
      getViewportDimensions();
      // We're currently throttled!
      throttled = true;
      // Reset throttled variable back to false after delay
      setTimeout(function() {
        throttled = false;
      }, delay);
    }
  }

  // Listen to resize event, and run throttler()
  window.addEventListener("resize", throttler);

  // End of IFFE wrapper
})();

Here’s a CodePen you can play with.

How to use your app on any project

Include a script tag at the bottom of your HTML document, just above your closing body tag (</body> ) and add the path to your js file, like this:

&lt;script src="/js/get-viewport-dimensions.js"&gt;&lt;/script&gt;

Browser Compatibility

Our app is compatible with all modern browsers, and from Internet Explorer 9 and up.

Advanced throttling

What we learned in this tutorial is a great precursor for some the more powerful performance tools on the market.

If you need to boost performance on more complex projects than the one we built, check out the Lodash JavaScript library. Lodash has a lot of performance features and is very popular among developers. You can also learn a lot from digging through the library’s code.

Resources

  • Mozilla’s Resize Event docs
  • Mozilla’s Frame Rate docs
  • Video on Response Times
  • Frame Rate vs Refresh Rate
  • Why 66ms when using setTimeout