최적화는 성능을 저해하거나 불필요한 코드들을 줄여 퍼포먼스를 극대화하는 과정을 말한다.
보통 브라우저의 로딩이 1초 느려질 때마다 고객들이 떠나가는 비율은 7% 이상이 된다고 하니, 브라우저의 화면에 필요한 정보가 빠르게 나오도록 만드는 과정은 몹시 중요하다.
E commerce와 같은 경우, 상품에 대한 이미지가 상당히 많기 때문에 그만큼 이미지 요청(src)가 많다.
그 말인 즉슨, 이미지를 로드 할 때 우선적으로 화면에 필요한 이미지만 로드를 하고, 나머지는 스켈레톤 프레임으로 로딩이 되기 전까지 대체를 하는 방안이 있을 수 있다.
또한, 이미지의 용량 역시 중요하다. 이미지의 타입은 크게 레스터와 벡터로 나뉘어진다
레스터 이미지는 픽셀 단위의 집합이 모여 하나의 이미지를 형성하는 것으로, 섬세하고 정교한 이미지를 만드려면 그만큼 픽셀 수가 늘어나고, 용량이 늘어난다.
벡터 이미지는 하나하나 수학적으로 계산된 연산결과로 이미지가 도출되는 형태로, 이미지의 크기가 확대되더라도 깨지지 않고 용량도 변하지 않는다는 장점이 있지만 이미지가 복잡해지면 복잡해질수록 연산할 내용도 많아져서 용량이 늘어나게 된다.
또한, 이미지는 손실이미지와 무손실 이미지라는 두가지 개념으로 분리가 가능하다.
손실 이미지는 jpeg와 같이 특정 이미지에 대해 표현에 필요한 내용을 제거하고 75~100% 사이에서의 품질을 가진 이미지를 뜻하고
무손실 이미지는 png와 같이 원본 이미지의 내용을 그대로 담고 있는 이미지를 말한다.
solution
이미지에 대한 최적화를 위해서는, img 태그에 있는 srcset 어트리뷰트와, sizes 어트리뷰트를 통해 구현할 수 있다.
srcset은 이미지경로와, 미디어쿼리 width를 나타내고있다. 즉, 뷰포트가 특정 크기 이하의 디바이스라면 자동으로 더 작은 리소스를 요청하도록 브라우저에게 해당 작업을 위임한다.
sizes는 불러온 이미지의 크기를 어떻게 설정할것인지에 대한 옵션이다. 앞에 적혀있는 미디어에 따라 이미지의 크기를 자동으로 조절한다
(media query를 추가적으로 입력할 필요는 없어지겠다)
또한 이미지를 CDN의 형태로 캐시로 전달하는 방법도 대안이 될 수 있다
필요한 값에 대해 만약 동일한 값이라면 다시 요청을 할 필요가 없다. 이에 따라 브라우저에 해당 데이터들을 저장하고, 굳이 요청을 할 필요가 없는 정적인 데이터라면 이 내용을 그대로 다시 사용하는 전략을 취한다
만약 해당 max age가 넘어버렸을 경우,
그때마다 또 새롭게 서버에게 요청을 날리는 것 역시 비효율적인 요청이므로, 이것을 더욱 최적화할 수 있다.
즉, 새로운 헤더옵션 (last modified) 를 설정하여놓고, 브라우저는 캐시데이터에 있는 age가 넘어갔을 때, 헤더에 if-modified-since라고 하는 옵션으로 자기가 갖고 있던 캐시데이터의 last modified를 전달한다. 브라우저는 이것을 비교하여 동일하다면 304 (not modified) 응답을 날린다.
그러면 브라우저는 해당 캐시의 max-age를 다시금 재설정하고 계속 사용하게 된다. (불필요한 데이터 교환 과정 삭제)
비교 대상을 날짜가 아닌 해시값(Etag)로도 할 수 있다( 이때 max-age 는 Etag와 대응되고, if-modified-since는 if-none-match와 대응된다 )
자바스크립트를 작성할 때 불필요한 로직은 성능상의 문제를 일으킬 수 있다. 여기에 React까지 더해지면 그 복잡도는 더 늘어나게 된다.
Javascript의 로직을 성능저하를 막으면서 제작하는 방법은 아래와 같다
targetString.split("").slice(2).join(""); // not like this
targetString.slice(2) // but like this
for(let key in Obj){
if(key === "a"){
// do something;
return;
}
}
loop1: for (let i = 0; i < haystacks.length; i++) {
loop2: for (let j = 0; j < haystacks[i].length; j++) {
if (haystacks[i][j] === needle) {
break loop1;
}
}
}
function doSomething(a,b){
function doSomethingElse(arg){
return process(arg);
}
return doSomethingElse(a) + doSomethingElse(b);
}
// not like above
// but like below
function doSomething(a,b){
function doSomethingElse(arg){
return process(arg);
}
return (a , b) => doSomethingElse(a) + doSomethingElse(b);
}
}