{"id":15642040,"url":"https://github.com/hg-pyun/performance-guide","last_synced_at":"2025-04-30T09:24:03.380Z","repository":{"id":91883493,"uuid":"96601201","full_name":"hg-pyun/performance-guide","owner":"hg-pyun","description":"Front-End performance guides","archived":false,"fork":false,"pushed_at":"2018-10-20T00:31:15.000Z","size":34,"stargazers_count":65,"open_issues_count":0,"forks_count":13,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-30T14:51:12.369Z","etag":null,"topics":["javascript","performance"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hg-pyun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-08T06:43:47.000Z","updated_at":"2024-01-17T09:15:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"866c8d4f-3add-4d60-a747-0cb544692efb","html_url":"https://github.com/hg-pyun/performance-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hg-pyun%2Fperformance-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hg-pyun%2Fperformance-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hg-pyun%2Fperformance-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hg-pyun%2Fperformance-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hg-pyun","download_url":"https://codeload.github.com/hg-pyun/performance-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251675342,"owners_count":21625794,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","performance"],"created_at":"2024-10-03T11:53:48.787Z","updated_at":"2025-04-30T09:24:03.354Z","avatar_url":"https://github.com/hg-pyun.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# performance-guide\n\u003e Depreacted, 현재 문서에서 다루고 있는 내용들의 대부분은 현대 자바스크립트 엔진 최적화 해주므로 더이상 신경쓰지 않아도 되는 부분이 많습니다.\n\n\nFront-End 개발시 성능 최적화에 대한 팁들을 정리해 놓은 가이드입니다. 이 문서는 syntax, convention, shorthand 등 전반적인 내용을 다룹니다.\n\n## Syntax\n\n#### || 연산자\n|| 연산자를 사용하면 코드량 및 연산 횟수를 줄일 수 있습니다.\n```javascript\nlet result;\nif (variable !== null || variable !== undefined || variable !== '') {\n    result = variable;\n}\nelse {\n    result = 'somthing';\n}\n\n// 위 문법은 다음과 같습니다.\nconst result = variable  || 'somthing';\n```\n\n#### \u0026\u0026 연산자\n||와 마찬가지로 \u0026\u0026 연산자를 사용하면 좀더 깔끔한 코드를 작성할 수 있습니다.\n```javascript\n// someProp이 존재하는지 체크한후 해당 함수 실행\nif(someObj.someProp){\n    someObj.someProp();\n}\n\n// 위 문법은 다음과 같습니다.\nsomeObj.someProp \u0026\u0026 someObj.someProp();\n```\n\n#### double exclamation mark\n!! 연산자를 사용하면 값의 유무를 판별할 수 있습니다.\n```javascript\n// 아래 경우를 제외하곤 true를 반환합니다.\n!!false === false\n!!0 === false\n!!\"\" === false\n!!null === false\n!!undefined === false\n!!NaN === false\n```\n\n#### scope 활용\njavascript는 객체를 내부 scope부터 외부로 점차적으로 탐색해 나갑니다.\n따라서 scope와 지역변수를 잘 활용하면 성능을 향상시킬 수 있습니다.\n```javascript\nfunction local(){\n    var id1 = document.getElementById(\"id1\");\n    var id2 = document.getElementById(\"id2\");\n}\n \n// 아 구문이 성능이 더 효율적입니다.\nfunction local(){\n    var d = document;\n    var id = d.getElementById(\"id1\");\n    var id2 = d.getElementById(\"id2\");\n}\n```\n\n#### innerHtml\ninnerHtml 횟수는 최소한으로 줄이는게 성능에 더 효율적입니다.\n```javascript\n// 루프를 돌때마다 reflow, repaint가 일어납니다.\nfor(var i=0; i\u003c100; i++){\n    document.getElementById(\"list\").innerHTML += \"\u003cli\u003elist\u003c/li\u003e\";\n}\n\n// 아래 구문이 성능이 더 효율적입니다.\nlet list = '';\nfor(var i=0; i\u003c100; i++){\n    list += \"\u003cli\u003elist\u003c/li\u003e\";\n}\n\ndocument.getElementById(\"list\").innerHTML = list;\n```\n#### loop syntax\n특별한 이유가 없다면 for in, forEach보다 for문을 사용하는게 좋습니다.\n(사실 적은 데이터에서는 실행 속도의 큰 차이는 없습니다.)\n```javascript\n- for (item in array)\n- forEach(function(item){})\n\n// 아래 구문이 성능이 더 효율적입니다.\nfor(var i=0; i\u003clength; i++){}\n```\n\n#### 변수 선언\n왼쪽의 문법이 오른쪽 문법보다 효율적입니다.\n```javascript\nvar arr = []; vs var arr = new Array();\narr[i] = i; vs arr.push(i);\nvar obj = {}; vs var obj = new Object();\nobj.a = 1; vs obj[\"a\"] = 1;\nvar str = \"test\"; vs var str = new String(\"test\");\n```\n\n#### array.length\narray 참조 횟수를 최소한으로 줄이는게 좋습니다.\n```javascript\n// loop를 돌때마다 array 참조가 일어남.\nvar i;\nfor (i = 0; i \u003c arr.length; i++){}\n\n// 아래와 같이 구현하는게 성능에 더 효율적입니다.\nvar i;\nvar l = arr.length;\nfor (i = 0; i \u003c l; i++) {}\n```\n\n#### array type\nArray의 type이 변경되면 성능 저하가 발생하므로 type이 변경되지 않도록 하는것이 좋습니다.\n또 Typped Array를 사용하는 것이 성능에 더 효율적입니다.\n```javascript\n// 아래 배열은 마지막에 string을 넣음으로서 배열 type이 변경됩니다.\nvar array = new Array(1000);\n\nfor(var i=0; i\u003c1000; i++){\n    array[i] = i;\n}\narray[999] = \"this is string\";\n\n// 아래 코드가 더 성능이 좋습니다.\nvar array = new Array(1000);\n\narray[0] = \"dummy\";\nfor(var i=0; i\u003c1000; i++){\n    array[i] = i;\n}\narray[999] = \"this is string\"; \n```\n\n#### 문자열 조합\n'+' 연산자보다 배열을 사용해서 조합하는게 성능에 유리합니다. 다만 최신브라우저의 경우에는 엔진이 최적화를 해주므로 '+' 연산자를 사용하는것이 유리합니다. (IE8 기준)\n```javascript\nvar str;\nfor (var i=0; i\u003c10000; i++) {\n\tstr += 'prefix'+i+'suffix';\n}\n\n// IE8 이하에서는 아래 코드가 더 효율적입니다.\nvar array = [];\nfor (i=0; i\u003c10000; i++) {\n\tarray.push('prefix', i, 'suffix');\n}\nvar str = array.join('');\n```\n\n#### array, object 할당\narray와 object는 한번에 초기화 및 할당하는 것이 좋습니다.\n```javascript\n/* array */\nvar array = new Array();\narray[0] = 1;\narray[1] = 1.5;\n\n// 아래 코드가 더 효율적입니다.\nvar array = [1, 1.5];\n```\n```javascript\n/* object */\n// var obj = {};\nobj.hello = 'hello';\nobj.world = 'world';\n\n// 아래 코드가 더 효율적입니다.\nvar obj = {\n    hello : 'hello',\n    world : 'world'\n}\n```\n#### Event\nEvent Binding으로 구현하는 것보다 Event Delegation이 성능이 더 효율적입니다.\n\n#### requestAnimationFrame\n시각적 변화를 위해 주기적으로 업데이트가 필요한 경우 setTimeout, setInterval보다 requestAnimationFrame을 사용하게는게 성능에 유리합니다.\n\n#### try ~ catch\ntry ~ catch 구문안에 있는 코드들은 컴파일러가 최적하지 못합니다.\n따라서 성능에 민감한 작업들은 함수로 한번 감싸주세요.\n```javascript\nfunction perf_sensitive() {\n  // 성능에 민감한 작업을 여기에서 처리합니다.\n}\n\ntry {\n  perf_sensitive()\n} catch (e) {\n  // 예외를 여기에서 처리합니다.\n}\n```\n\n#### 함수 선언문 vs 함수 표현식\n함수 선언문을 사용하면 스코프 최상단으로 [호이스팅](https://perfectacle.github.io/2017/04/26/js-002-hoisting/)되므로 프로그램이 의도적으로 동작하지 않을 수 있고,  \n스크립트를 로딩했을 때 [VO(Variable Object)](http://mohwa.github.io/blog/javascript/2015/10/14/vo-inJS/)에 할당하기 때문에 성능상 이슈도 존재합니다.  \n```javascript\nalert(x); // function x() {}\nif(x === undefined) { // 실행되지 않습니다.\n  alert('나는 아직 할당되지 않았어!');\n}\n\nvar x = 2;\nfunction x() {}\nalert(x); // 2, 변수 x를 생성하고 할당한 것 이후에 함수 x를 선언했지만 호이스팅에 의해 의도치 않게 동작합니다.\n```\n\n위와 같은 이유로 인해 함수 표현식 사용을 **권장**합니다.  \n```javascript\nalert(x); // undefined\nif(x === undefined) { // 드디어 실행됩니다.\n  alert('나는 아직 할당되지 않았어!');\n}\n\nvar x = 2;\nx = function(){};\nalert(x); // function(){}\n```\n\n## HTML\n#### script tag\n브라우저가 script 태그를 만나면 script 태그가 처리될때까지 body의 로드가 지연됩니다. \n따라서 script 태그는 head보다 body밑에 넣는것이 사용자가 view를 더 빨리볼 수 있습니다.\n```html\n\u003chtml\u003e\n\u003chead\u003e\n    \u003cscript\u003esome script\u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    something\n\u003c/body\u003e\n\u003chtml\u003e\n\n// 아래 코드가 사용자 입장에서 더 효율적입니다.\n\u003chtml\u003e\n\u003chead\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    something\n\u003c/body\u003e\n\u003cscript\u003esome script\u003c/script\u003e\n\u003chtml\u003e\n```\n\n## Build\n#### concat\n다수의 script를 따로 배포하는 것보다 하나의 파일로 합친 후에 서빙하는 성능에 유리합니다.\nscript를 합치기 위해서는 [gulp](http://gulpjs.com/), [grunt](https://gruntjs.com/) 같은 task runner를 사용하거나 [webpack](https://webpack.js.org/) 같은 bundler를 사용하면 좋습니다.\n\n#### minify \u0026 uglify\nminify는 불필요한 공백을 제거하는 작업이고, uglify는 코드 난독화 및 production에서 불필요한 코드(console.log)를 제거해주는 작업입니다.\n해당 작업을 통해 용량을 줄이고 코드를 최적화 할수 있습니다. 대부분의 task runner나 webpack 등을 사용해서 작업할 수 있습니다.\n\n#### tree shaking\n```javascript\n// module.js\nexport const a = 123123123123;\nexport const b = 45645646456;\n\n// app.js\nimport {a} from './module';\nconsole.log(a);\n```\n위와 같은 코드가 있을 때 쓰지 않는 변수, 불필요한 변수 b를 제거하는 것을 **트리 쉐이킹**이라고 한다.  \n나무를 흔들어 썩은 열매를 떨어뜨리는 행위에서 유래한 것 같다.  \n[webpack](https://webpack.js.org/)이나 [rollup](https://rollupjs.org/)과 같은 모듈 번들러에서 제공한다.  \n\n#### gzip\n기존의 js, css 파일 등등은 위의 과정들을 거쳐 최적화를 시켜도 인터넷 속도가 느린 환경에서는 여전히 제약사항이 된다.  \n이를 위해서 해당 asset들을 gzip 압축 알고리즘을 통해 압축을 하면 파일 용량이 훨씬 작아진다.    \n이미 압축이 많이 된 이미지나 동영상 등등은 압축을 한다 한들 별 소용이 없다.  \n또한 파일 용량이 매우 작은 경우에는 압축을 푸는 시간이 오히려 압축되지 않은 파일을 내려받는 속도보다 느릴 수도 있기 때문에 일정 용량 이상부터 압축을 해야한다.  \n이를 위해서는 서버 쪽에서도 설정이 필요하다.\n\n#### caching\nHTTP 1.1 표준 스펙에는 하나의 요청 당 하나의 응답, 즉 하나의 파일만이 서비스가 가능합니다.  \n요청을 보내고 응답을 받기까지 불필요한 작업들로 인해 오버헤드가 발생합니다.  \n따라서 하나의 HTML 파일을 보기 위해 여러 파일(css, js, 이미지 등등)을 받아야하는 단점이 존재합니다.  \n그럼 HTML 파일 안에 넣을 수 있는 소스들을 모두 넣어서 요청을 최소화하는 것이 더 좋지 않을까라는 의문점이 들게 되기 마련입니다.  \n그에 대한 해법을 찾기 위해 다음과 같은 상황을 가정해봅시다. (로딩 속도도 임의로 가정해서 정확하지 않습니다.)\n\n|                                     | HTML 다운로드 속도 | HTML 해석 속도 | 요청에 따른 오버 헤드 | asset 다운로드 속도 | asset 해석 속도 | 총 로딩 속도 |\n|-------------------------------------|--------------------|----------------|-----------------------|---------------------|-----------------|--------------|\n| HTML 파일에 전부 존재(처음 접속)    | 2s                 | 1s             | 0s                    | 0s                  | 1s              | 4s           |\n| HTML과 asset 파일들 분리(처음 접속) | 1s                 | 1s             | 1s                    | 1s                  | 1s              | 5s           |\n\n페이지를 처음 방문 했을 때는 HTML 파일 하나에 몰아넣은 경우가 더 빠릅니다.  \n하지만 다양한 상황에 대해 페이지를 재방문 했을 때는 어떨까요?\n\n* HTML 파일만 수정한 경우\n\n|                                  | HTML 다운로드 속도 | HTML 해석 속도 | 요청에 따른 오버 헤드 | asset 다운로드 속도 | asset 해석 속도 | 총 로딩 속도 |\n|----------------------------------|--------------------|----------------|-----------------------|---------------------|-----------------|--------------|\n| HTML 파일에 전부 존재(재접속)    | 2s                 | 1s             | 0s                    | 0s                  | 1s              | 4s           |\n| HTML과 asset 파일들 분리(재접속) | 1s                 | 1s             | 0s(caching)           | 0s(caching)         | 1s              | 3s           |\n\n* asset 파일만 수정한 경우\n\n|                                  | HTML 다운로드 속도 | HTML 해석 속도 | 요청에 따른 오버 헤드 | asset 다운로드 속도 | asset 해석 속도 | 총 로딩 속도 |\n|----------------------------------|--------------------|----------------|-----------------------|---------------------|-----------------|--------------|\n| HTML 파일에 전부 존재(재접속)    | 2s                 | 1s             | 0s                    | 0s                  | 1s              | 4s           |\n| HTML과 asset 파일들 분리(재접속) | 0s(caching)        | 1s             | 1s                    | 1s                  | 1s              | 4s           |\n\n* HTML 파일과 asset 파일 모두 수정한 경우\n\n|                                     | HTML 다운로드 속도 | HTML 해석 속도 | 요청에 따른 오버 헤드 | asset 다운로드 속도 | asset 해석 속도 | 총 로딩 속도 |\n|-------------------------------------|--------------------|----------------|-----------------------|---------------------|-----------------|--------------|\n| HTML 파일에 전부 존재(재접속)    | 2s                 | 1s             | 0s                    | 0s                  | 1s              | 4s           |\n| HTML과 asset 파일들 분리(재접속) | 1s                 | 1s             | 1s                    | 1s                  | 1s              | 5s           |\n\n위와 같이 파일이 수정되지 않은 경우에는 브라우저의 임시 폴더에 존재하는 파일을 불러오는 **캐싱**을 이용할 수 있습니다.  \n하지만 HTML 파일 하나에 모든 소스를 넣어두면 조그만 수정이 있다 하더라도 파일 전체를 새로 내려받아야해서 이런 캐싱의 장점을 이용할 수 없습니다.  \n따라서 이런 캐싱의 장점을 살리기 위해 html, css, js 파일은 최대한 분리시켜 놓는 게 좋습니다.  \n\n# Contribute\n#### Document convention\n가장 큰 카테고리는 '##'을 사용합니다.\n카테고리 안에서 소분류는 '####'을 사용합니다.\n```\n// example\ncategory : ## Javascript\ns-category : #### closure\ncontents : this is closure \nexample : use ```  \n```\n\n#### Pull Request\n새로운 내용이나 수정은 Pull Request형식으로 보내주시길 바랍니다. 또한 이 문서는 누구나 수정할 수 있으며 재배포시 출처를 꼭 밝혀주시길 바랍니다.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhg-pyun%2Fperformance-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhg-pyun%2Fperformance-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhg-pyun%2Fperformance-guide/lists"}