과거 Javascript에 대해서는 거의 문외한이던 시절 처음 React를 배워 교내 프로젝트를 하던 때 뭔지도 모르고 만들었던 Javascript 코더에서 벗어났다는 느낌을 받은 날이었다. 컴포넌트 단위로 코드를 분리하여 관리하는 방식을 배우고, 비동기 방식에 대해 배웠다.
html에서 script:src로 script를 관리하는 방법, 모듈 단위로 관리하는 방법 2가지를 모두 배워봄으로써 모듈 단위 관리의 중요성을 직접 경험해볼 수 있었고, 비동기 파트에서는 async/await만 잘 쓰면 되겠지 싶었던 생각을 뜯어고칠 수 있었다.
Vanila JS에 대해 제대로 배우기 시작한지 고작 이틀 밖에 안되었지만, 과거에는 JS에서 왜 컴포넌트 단위로 관리를 하는지, 왜 비동기를 써야하는지 등 이유를 모르고 있었기에 제대로 쓸줄도 모르고, 써야하는 이유도 몰랐다. 오늘 그 이유를 배웠기에 나는 과거에서 탈출했다고 할 수 있다.
또한 JS는 다른 언어들에 비해 비논리적인 괴랄한 언어라는 인식에서 벗어난 날이었다. 어떤 언어든 장점과 단점은 트레이드 오프 관계이다. 어떤 언어든 장점만 존재하지 않는다. 하나의 장점을 살리면 하나의 단점을 만들어 낸다. 다만 JS는 초기에 단점이 좀더 두드러져 보였고, 버전을 거듭할수록 효율적인 방향으로 진화하고 있다. 그 자리에 정체되어 있지 않고, 보다 나은 방향으로 변화하고 발전해 나가는 언어라는 점에서 최근들어 JS라는 언어가 점점 매력적으로 보인다.
import: export 키워드로 보내지는 변수, 함수 등을 불러올 수 있는 키워드
export default myFunc;//내보내는 파일에서 선언
import defaultExport from 'module-name';//내려받는 파일에서 선언
export: 여러개의 변수와 함수를 가져올 수 있다.
import * as allItems from 'module-name';
모듈을 쓰는 경우 html에서 script 선언할 때 맨처음에 불러오는 entry 모듈의 경우, type으로 module을 명시해야 한다
<script src="./src/index.js" type="module"></script>
import {loadItem} from 'module-name';
import {loadItem as loadSomthing} from 'module-name';
import/export
를 활용함으로써 기존의 script:src
를 사용하거나 의존되는 순서대로 스크립트 로직을 테트리스 하듯이 쌓을 필요가 없어진다.import/export
를 활용하면 사용/미사용 스크립트
를 쉽게 분류할 수 있다.js
별로 사용되는 모듈을 명시적으로 import
해오기 때문에, 사용되거나 사용되지 않는 스크립트를 추적할 수 있다.script tag
로 로딩하는 경우 불러오는 순서가 중요하지만, import
로 불러오면 순서는 무관하다script src
로 불러오는 것과 달리 전역오염이 일어나지 않는다.from
이후 모듈 이름 맨 뒤에 '.js'를 안붙여서 발생하는 경우가 많다.function onButtonClick(){
alert('clicked');
}
document.querySelector('.save-button').addEventListener('click',onButtonClick);
첫 번째 인자로 넘겨진 함수는 바로 실행되지 않고, setTimeout
or setInterval
의 시간만큼 지난 후에 실행된다.
function work(){
console.log('works')
}
setTimeout(work,1000);
setInterval(work,5000);
console.log('work process');
// work process
// works
// works.
// ...
setTimeout
의 시간을 0으로 넣거나 지정하지 않아도 바로 실행되진 않는다
-> setTimeout
과 같은 함수들은 무조건 work()
가 모두 실행되고 난 이후에 실행된다.
function work(){
console.log("start work");
setTimeout(function(){
console.log('working');
},0)
console.log("finish work");
//start work
//finish work
//working
}
비동기 처리의 원리
JS 엔진을 보면
call stack
,web api
,task queue
가 존재하는데,call stack
에setTimeout()
이 호출되면web API
에 있는 함수이므로 해당 함수를 호출하여call stack
에서 비운뒤Web API
에서 함수를 처리한뒤 콜백함수를task queue
에 등록한다. 그리고 난 다음에event loop
에서call stack
이 비는지 관찰하고 있다가,call stack
이 비면 그때task queue
에 있는 함수들을 순차적으로 요청사항에 맞게 실행하게 된다.
XHR(XMLHttpRequest) (~= AJAX): 데이터를 비동기로 요청하고, 요청 후의 동작을 비동기로 처리한다.
function request(url,successCallback,failCallback){
const xhr=new XMLHttpRequest();
xhr.addEventListener("load",(e)=>{
if(xhr.readyState===4){
if(xhr.status===200){
successCallback(JSON.parse(xhr.responseText));
}else{
failCallback(xhr.statusText);
}
}
})
xhr.addEventListener('error',(e)=>failCallback(xhr.statusText));
xhr.open('GET',url);
xhr.send();
}
(sync방식을 쓰면 가독성이 워낙 좋아지니 복잡한 async대신 sync를 쓰고 싶다는 유혹이 생길 수 있다. 그러나.. sync 방식을 사용하게 되면 요청 후 응답이 오기전까지 브라우저가 굳어져버린다!!! .. 콘솔에서도 sync XMLHttpRequest는 warning을 준다)
Promise.all(iterable)
: 여러 promise를 동시에 처리할 때 유용하다.const promise1=delay(1000);
const promise2=delay(2000);
const promise3=delay(3000);
Promise.all([promise1,promise2,promise3].then(()=>{
console.log("works done");//6초후에 실행됨
}))
Promise.race(iterable)
: 여러 promise중 하나라도 resolve
또는 reject
되면 종료된다.
Promise.any(iterable)
: 여러 promise중 하나라도 resolve
되면 종료된다.
Promise.allSettled(iterable)
: 여러 promise들이 성공/실패 상관없이 모두 이행된 경우를 처리한다.
Promise.resolve
: 주어진 값으로 이행하는 Promise.then 객체를 만든다. 그리고 주어진 값이 Promise
인 경우 해당 Promise가 반환
된다.
const cached={
'roto':'guitar'
}
const findMember=(memberName)=>{
if(cached[memberName]){
return Promise.resolve(cached[memberName]);
//Promise객체를 리턴함
//Promise 없이 resolve()만 하면 String이 리턴되어, 함수 호출시 then에서 값을 받을 수 없어 에러가 발생한다. 따라서 Promise.resolve()를 하여 Promise객체를 리턴해준다.
}
//(request()는 걍 만든 Promise함수임)
// then()에서 리턴을 하면 무조건 Promise객체를 만들기 떄문에 findMember().then()에 대응할 수 있다.
return request(`/members/${memberName}`).then((member)=>{
cached[member.memberName]=memberName;
return memberName;
})
}
findMember('roto').then((memberName)=>console.log(memberName));
// 방법1
async function asyncFunc(){
const res=await request(...);
}
// 방법2
const asyncFunc=async (){
const res=await request(...);
}
resolve
, reject
, finally
를 통한 예외처리는 try..catch..finally
를 쓰면 된다.