사용자가 다른 페이지로의 이동을 요청하면 서버에서 페이지에 해당하는 html 파일로 응답을 해주고, 브라우저가 해당 파일을 받아 해석한 후 사용자에게 보여주는 방식으로 사용자에게 보여주는 화면을 서버측에서 준비를 했다.
요즘에는 웹에서 제공되는 정보가 매우 많기 때문에 새로운 화면을 보여 주어야 할 때마다 서버 측에서 모든 페이지를 준비하게 되면 성능상의 문제가 발생할 수 있다.
ex)
1. 트래픽 과다
2. 사용자가 동시간대에 몰릴경우 서버에 무리를 줄 수 있다.
3. 새로운 페이지로 이동( 화면 전환 ) 할 때 마다 새로운 html 파일을 계속해서 유저와 서버가 요청/응답 하게 되면 상태 유지가 번거로울 뿐만 아니라 불필요한 페이지 로딩이 발생하게 되어 비효율적이다.
► React같은 라이브러리 or 프레임워크를 사용하여 유저의 브라우저가 뷰 렌더링을 담당하도록 하면 이러한 성능상의 문제를 해결할 수 있다.
Single Page Application
SPA는 이름 그래도 하나의 페이지로 이루어진 애플리케이션이라는 의미이다. SPA의 동작 방법은 아래의 그림과 같다.
사용자가 처음 서버에 접속 요청을 보내면 html 파일과 함께 정적 리소스 파일들을 함께 보내준다. 이후에 유저가 서버에게 요청을 하면 해당 요청에 필요한 JSON 파일들만 응답해주며 브라우저는 서버에게 받은 JSON파일을 해석하여 변경된 사항만을 반영하여 유저에게 보여준다.
► SPA의 경우 페이지는 한 종류이지만, 해당 페이지에서 로딩된 JS와 현재 사용자 브라우저의 주소 상태에 따라 다양한 화면을 보여줄 수 있다. ( 다른 주소에 다른 화면을 보여주는 것을 라우팅 이라고 한다. )
[ + ] 리액트 라우팅 라이브러리 종류
1. react-router
2. reach-router
3. Next.js .. 등
SPA의 단점
1. SPA의 단점은 앱의 규모가 커지면 JS 파일의 크기가 너무 커진다는 것이다. ( 페이지에 첫 방문 시 정적 리소스들을 html 파일과 함께 모두 보내주기 때문에 ) 페이지 로딩 시 사용자가 실제로 방문하지 않을 수도 있는 페이지의 JS도 함께 불러오게되기 때문이다.
→ 코드 스플리팅 ( code spliting ) 을 사용하면 라우트별로 파일들을 나누어서 트래픽과 로딩 속도를 개선할 수 있다.
2. SEO ( Search Engine Optimization ) 검색엔진최적화 문제
JS를 실행하지 않는 일반 크롤러에서는 페이지의 정보를 제대로 수집해가지 못하여 검색 엔진의 검색 결과에 페이지가 나타나지 않을 수도 있다. → 검색엔진에 나타나지 않는다는 것은 큰 문제 ( 광고, 홍보, 유저가 구글, 네이버 등 포탈에서 검색을 통해 유입되지 못함. )→ SSR ( Server Side Rendering ) 을 통해 해결할 수 있다.
3. JS가 실행될 때까지 페이지가 비어 있기 때문에 JS 파일이 로딩되어 실행되는 짧은 시간 동안 흰 페이지가 나타날 수 있다. → SSR ( Server Side Rendering ) 을 통해 해결할 수 있다.
function 함수<Type>( x: Type[] ) : Type{
return x[0];
}
let a = 함수<number>([4,2]);
let b = 함수<string>(['4','2']);
console.log(a); // 4 ( number )
console.log(b); // '4' ( string )
Generic Type 제한
아래와 같이 함수의 타입이 extends된 속성을 가지고 있는지를 확인
커스텀 타입으로도 타입파라미터 제한이 가능하다.
function 함수<Type extends number>( x: Type[] ) : Type{
return x[0];
}
let a = 함수<number>([4,2]);
console.log(a); // 4 ( number )
interface LengthCheck {
length : number
}
function 함수<Type extends LengthCheck>( x: Type[] ) : Type{
return x.length;
}
let a = 함수<string[]>(['100']);
console.log(a); // 1
function solution(s) {
let answer = 0;
let left = '';
let right = '';
let result = [];
for (let i = 1; i < Math.ceil(s.length / 2) + 1; i++) {
result.push([]);
// i = length
let cnt = 1;
for (let k = 0; k < s.length; k++) {
left = s.substr(k * i, i);
right = s.substr((k * i) + i, i);
if (left === right) {
cnt += 1;
}
else {
// 똑같은 문자열이 있는 경우 숫자와 문자열을 같이 저장
if (cnt > 1) {
result[i - 1] += String(cnt) + left;
}
// 똑같은 문자열이 없는 경우 문자열만 저장
else {
result[i - 1] += left;
}
cnt = 1;
}
}
}
let min = result[0].length;
for (let i in result) {
if (min > result[i].length) {
min = result[i].length;
}
}
return min;
}
나는 len/2 => len/3 => len/4 순서로 크게크게 조각내서 비교를 했다면 이분은 작은 조각 => 큰 조각 순으로 비교를 하였다.
하이라이트 되어 있는 부분인 첫 번재 for문이 바로 주어진 문자열을 조각내는 부분이다.
해당 for문에서 var tmp = s.substring(0,len); 을 console.log로 찍어주면 아래와 같이 찍히는 것을 확인할 수 있다.
// input string
"aaaaaaaaaabbccc"
console.log() 결과
두 번째 for문
두 번째 for문의 경우 첫 번째 for문에서 조각난 tmp를 제외한 뒷 부분의 문자열들을 tmp와 같은 크기로 조각내어 tmp값과 비교 한 후 tmp와 값이 같으면 counting 값인 cnt 값을 ++ 해준다.
만약 tmp값과 같지 않으면서 cnt 값이 1인경우는 앞에서 tmp값과 same이었던 적이 없음으로 str에 tmp를 그대로 넣어주고, cnt를 1로 초기화 시켜 준 후 tmp값을 현재의 값으로 update해준다. => 다음 substring값과 같은지 비교하기 위해서
만약 tmp값과 같지 않으면서 cnt값이 1이 아닌 경우는 앞에서 tmp와 값이 같았던 적이 있음으로 cnt+tmp값을 str에 넣어주고 tmp값을 현재의 값으로 update해준다.
첫 번째 for문의 마지막 if~else 구문은 맨 마지막 문자의 처리를 해주는 것이다.
그 다음 줄의 answer.Math.min(answer, str.length); => Math의 내장함수인 min()을 이용하여 answer와 str의 길이 중 더 짧은 값을 answer에 저장해준다. answer의 초깃값은 처음 들어온 string.length로 하나도 조각 나지 않는 경우도 있을 경우를 위해 string.length로 초기화를 시켜준 것이다. answer값을 for문을 돌 때마다 update되며 마지막에는 가장 작은 값으로 update되게 된다.