저번 글에서 setTimeout을 해부하게 된 건 전적으로 요 과제 때문이었다.
교수님께서 내가 차면 상대방이 자동으로 1초 뒤에 차게끔 코딩해보라고 하셔서 딜레이를 사용했고,
승부차기 특성상 일정 점수 이상을 먼저 따면 중간에도 승패가 갈리게끔 코딩하고 싶었다.
그래서 중간중간 점수를 확인하면서 승패가 안 났을 때만 버튼을 활성화시키도록 했는데,
그냥 setTimeout(function , 1000), setTimeout( , 2000) 이런 식으로 순서를 주려고 했더니 위에서 딜레이를 실행하는 동안 밑에서 현재 점수로 검사하고 지맘대로 게임을 끝내버린 후 점수를 누적시켜서 다시 검사하더라.... 그래서 한국 차고 일본 차는 중인데 갑자기 한국 승! 나오더니 다시 일본이 차고 경기를 이어가거나 비겼다고 하는 둥 가관이었다
정말 콜백이고 비동기고 아직 많이 불편하다 비동기 모드 동기 모드 있었으면 좋겠음
비동기적 처리란 이처럼 특정 동작이 끝날 때까지 기다려주지 않고 다음 코드를 그냥 쭉쭉 실행하는 처리를 말한다. 자바스크립트는 비동기적 처리를 하는 데 그 대표적인 예가 setTimeout이었고...ㅠㅠ
그래서 외면하려던 callback, promise, async/await을 울며 겨자먹기로 공부해서 적용해봤다. 물론 공부는 했지만 아직 손이나 머리에서 낯을 가려서 완벽하진 않다는 점 양해...
호이스팅, 콜백
공부한지 오래 돼서 복기하려니 잘 기억이 안 나는데, 일단 자바스크립트는 밑에서 선언한걸 위에서 써도 알아먹는 호이스팅이라는 걸 하고 코드를 읽는다.
a; //콘솔 출력 없음
var a = function test(){
console.log('dddd');
}
이런 식으로 내가 a; 를 먼저 호출하고 밑에서 var a = fucntion test(){...}; 하면
씨언어는 미쳤냐 선언도 안 하고 어케 써 하면서 에러를 띄우지만
자바스크립트는 알아서 var a를 위로 올려 선언해준 후 읽기 때문에 에러가 안 난다.
test(); //console 출력 : dddd
function test(){
console.log('dddd');
}
이러한 특성 덕분에 밑에 선언하고 위에서 호출해도 아무런 문제가 없다.
이게 좀 양날의 검인 것 같은 게 순기능만 따지면 씨언어처럼 메인 코드를 위로 올리고 함수 부분을 밑에 모아놓기 위해 밑에서 구현한 함수들을 위에서 다시 선언해줘야하는 불편함이 줄어들지만,
맨 위 코드에서 a를 호출했을 때 콘솔 출력이 일어나지 않는 것처럼 의도한대로 되지 않았는데도 에러가 없어서
? 뭐야 왜 안돼 의 순간들이 오고 마는 것이다. 가끔은 툭하면 에러를 내뱉던 철벽킹 단호박 씨언어가 그리워질 것 같다...
뭐 이런 호이스팅이란 걸 하고 나서 다음거 안 기다리고 지 갈길 가는 비동기적으로 코드를 읽고 실행해나가는데, 이러면 나처럼 원하는 때에 딜레이 기다려주는 코드를 짜기가 어렵지 않겠는가?
그래서 자기가 실행하고 싶은 때에 맞춰서 실행하는 동기적 처리를 하게끔 콜백이라는 걸 쓰는 것이다. 이 구조에 강력 반대하는 나는 별로 살펴보고 싶지 않다. 그러니까 단점인 콜백 지옥만 보자.
$.get('url', function(response) {
parseValue(response, function(id) {
auth(id, function(result) {
display(result, function(text) {
console.log(text);
});
});
});
});
콜백을 쓰면 동기적으로 처리할 부분을 쭈욱 묶어서 써야 하는데, 코드가 길어지면 코드들을 오른쪽으로 날려버리게 된다. 읽을 때도 쓸 때도 수정할 때도 이마를 짚게 되는 구조다.
위 코드는 일일이 빼서 인자로 다른 함수를 받게끔 해서 다른 함수를 또 선언해주는 것을 반복해도 되지만, 함수를 필요보다 많이 선언하게 되고 내가 원하는 형태에 적용할 수 있는 형식이 아니기 때문에 굳이 자세히 살펴보지 않겠다.
promise, async/await
new promise 를 쓰고 .then 으로 이어서 사용하면 콜백함수처럼 사용할 수 있지만, 여기서는 async와 await을 이용하기 위해 구조만 이해하고 넘어가보겠다.
우선 promise에는 세가지 상태가 있다고 한다. 대기, 이행, 실패.
new Promise() 메서드를 호출하면 대기 상태가 되는데, 호출 시 인자가 resolve, reject인 콜백함수를 선언할 수 있다.
new Promise(function(resolve, reject){
resolve();
});
new Promise(function(resolve, reject) {
reject();
});
resolve와 reject는 각각 이행, 실패 상태이다. 이는 코드가 완료된 상태와 오류가 발생한 상태를 표현할 때 사용 가능하다. 오류 시 reject 내용을 담은 new Promise를 return으로 받은 함수 뒤에 then().catch() 형식으로 코딩을 할 수 있다.
ex) test().then().catch(function(){ ... })
promise의 구조를 이해했으면 async와 await의 사용은 간단하다.
1. 동기처리가 필요한 시작점이 되는 함수에 async를 붙여 선언하고
2. async로 선언한 함수 안에 그 함수를 기다렸다가 바로 뒤에 실행될 함수들을 호출할 때 앞에 await을 붙이면 된다.
글보다 보는 것이 더 쉬우니 내 코드로 설명해보겠다.
async function myturn(){
if(shootType === 1){ ... }
else{ ... }
await comturn();
await finish();
}
function comturn(){
return new Promise(function(resolve, reject){
setTimeout(function(){ //상대 턴 딜레이(1초)
if(shootType === 1){ ... }
else{ ... }
resolve("턴 종료");
},1000);
})
}
function finish(){ //2점 차이나거나 5턴 돌고 결과(2초 후)
return new Promise(function(resolve, reject){
if(myScore >= comScore+2 || (shootcnt >= 5 && myScore > comScore)){
setTimeout(function(){ ... },2000);
}
else if(comScore >= myScore+2 || (shootcnt >= 5 && myScore < comScore)){
setTimeout(function(){ ... },2000);
}
else if(shootcnt >= 5 && myScore===comScore){
setTimeout(function(){ ... },2000);
}
else { ... }
resolve("게임 종료");
});
}
(이해에 방해가 될 것 같은 줄들은 최대한 빼고 setTimeout 위주로 남겼다)
이렇게 코딩하면 내턴 실행 > 컴퓨터턴 실행 > 점수 검사 순으로 딜레이를 맞춰 실행하게 된다.
사실 마지막에 resolve 안에는 아무것도 안 넣어도 똑같고, 주석느낌으로 넣은 건데
게임 종료는 조금 안 맞는 것 같다. 내턴 컴퓨터턴 합친 한턴이 종료되는 느낌인데 대체할 말이 마땅치 않아서 그냥 넣었다.
함수를 길게 짜면 콜백이나 promise로 동기처리를 하기 불편한 감이 있는 것 같다. 아무래도 함수를 짜놓고 딜레이를 맞출 때는 async await을 쓰기가 편하다보니 앞으로도 필요하다면 async await을 쓰지 않을까 싶음.
오늘 공부 끝!!!!!
쓰면서 참고한 블로그 : joshua1988.github.io/web-development/javascript/promise-for-beginners/
여기 블로그 정리 잘해놨더라. 가끔 공부할 때 들러볼 생각ㅎ.ㅎ
'블록체인 기반 핀테크 및 응용 SW 개발 > Javascript' 카테고리의 다른 글
블로킹/논블로킹, 스레드 - 싱글/멀티 스레드 정리 (0) | 2021.02.16 |
---|---|
[JavaScript] setTimeout()의 형식과 익명함수, arrow 함수 공부 (1) | 2021.01.11 |