일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- css-in-js 버그
- State
- redux
- react-naver-map
- prop 'className' did not match
- UI컴포넌트설계 고민
- 유사이터럴객체의차이
- 오랜만의회고
- 설치 및 구조파악
- 트러블슈팅
- 컴파운드패턴 연습
- 2번째
- nextjs13
- 두번째포스팅
- Promise
- thunk정리
- 언어학습2일차
- 함수형업데이트
- useState
- 프로젝트회고
- 항해99
- styled-component
- RSC
- WIL
- 이미지로딩실패
- RCC
- props
- getElements
- til
- react
- Today
- Total
코딩을 박터지게 죽을때까지
동기/비동기 promise async/await 학습중에 알게 된 것들. 본문
인데... async부분을 좀 더 자세히 보고 싶어서..
일단 나중에 좀 더 머리로 내용을 정리해서 쓸 생각.
그전에, 오늘 좀 공부하다가 알게 된 것
사실 이것때문에 진도가 늦어졌다.
프로미스 파트를 읽다가 예제 문제가 나왔다.
1) 버튼을 누르면 빈공간에서 작은원이 점점 커져서 나타남(2초동안)
2) 그리고 다 커지면 가운데에 안녕하세요 글귀가 나옴.
https://plnkr.co/edit/cbR8Y1l11SL5Sdmo?p=preview&preview
Plunker - Code example
Plunker is loading… It's really nice to see you today!
plnkr.co
위의 문제임. 정확히는 그 문제의 해답인데 실행결과가 링크된 웹사이트의 오른쪽 프레임에 나오니까 참고.
일단 내 방식대로 먼저 풀어서 똑같이 구현은 했으나 조금 다르게 구현했다.
먼저, 아래와 같이 showCircle 이라는 함수를 정의했다.
const x = 150;
const y = 150;
const rad = 100;
const btn = document.getElementsByTagName('button')[0];
function showCircle(vertical, helical, radius) {
return new Promise((resolve, reject) => {
let div = document.createElement('div');
div.id = "temp";
div.style.width = 0;
div.style.height = 0;
div.style.left = vertical + 'px';
div.style.top = helical + 'px';
div.className = 'circle';
document.body.append(div);
setTimeout(() => {
div.style.width = radius * 2 + 'px';
div.style.height = radius * 2 + 'px';
if (Math.random() > 0.5) {
resolve(div, div.style.transitionDuration);
} else {
reject(new Error("에러임"));
}
}, 0);
});
}
setTimeout을 0초로 주고,
난수를 생성해서 50%확률로 성공(resolve)하거나 실패(reject)한다.
그 다음, 버튼의 이벤트리스너 구현을 했다.
btn.addEventListener('click', () => {
showCircle(x, y, rad)
.then(div => {
const time = Number(getComputedStyle(document.getElementsByClassName('circle')[0])
.transitionDuration[0]) * 1000;
setTimeout(() => {
div.classList.add('message-ball');
div.append('Hello, world!');
}, time);
})
.catch(error => {
const time2 = Number(getComputedStyle(document.getElementsByClassName('circle')[0])
.transitionDuration[0]) * 1000;
setTimeout(() => {
console.log(error);
}, time2);
});
});
해답에서는 이벤트리스너를 "transitionend" 로 설정하고, 이벤트리스너를 제거해줬는데,
이게 무슨 의미인지는 좀 잘 모르겠다. 나중에 한번 이벤트리스너를 깊게 공부해봐야 할 것 같다.
아무튼 나는 이렇게 짰음.
이벤트리스너의 콜백으로 showCircle 프로미스를 실행하는데,
then 내부의 콜백함수에서, setTimeout에 들어가는 시간 파라미터의 값을 참조해 올 대상이 필요했다.
이 코드는 css 내부에서 아래와 같이 클래스가 정의되어 있다.
.circle {
transition-property: width, height, margin-left, margin-top;
transition-duration: 2s;
position: fixed;
transform: translateX(-50%) translateY(-50%);
background-color: red;
border-radius: 50%;
}
.message-ball {
color: black;
font-size: 20px;
line-height: 200px;
text-align: center;
}
transition-duration이 2초로 설정되어 있는데,
이거를 보고 setTimeout에 내 손으로 2000을 직접 기입하지 않고,
실제 요소 참조를 통해서 저 값을 가지고 오고 싶었다.
즉, transition 시간이 몇초가 되든 프로그램이 동적으로 대응하여 완벽하게 돌아가게 만들고 싶었다.
그래서 나는
요소.Style.transitionDuration 을 처음에 인자로 넘겨주었으나, 실행되지 않았다.
콘솔을 찍어본 결과,
이와 같이 아무런 값이 들어가 있지 않은 것으로 나타난다. 여기서부터 오늘의 나의 고통이 시작됐다.
과연 동기/비동기를 공부하는 것인지 DOM을 공부하는 것인지..
아무튼 DOM공부도 병행하고 있던 나의 입장에서는 뭔가 납득할 수가 없어서
요소.style를 찍어 봤더니 js코드로 인해서 입력된 top,width 등의 사이즈를 제외한 모든 수치들
즉 css에 입력되어있는 값들이 전혀 들어가 있지 않았다.
개발자도구의 요소를 들어가보면,
코드 실행 후에 찍히는 html은 아래와 같다.
태그안에 있는 style 속성에 있는 값만 리스팅이 되는 것이다. 새로운 것을 알았다.
자, 그럼 이제 css에 정의된 값들은 어떻게 가져와야할까?
그러던 중에 Window 객체에 속해 있는 함수를 발견했다.
이 함수는 파라미터로 입력된 객체에 입혀진 모든 계산된 스타일을 땡겨온다...
세상 피곤하게 이걸로 접근해야하나.. 싶었지만 그래도 검색결과가 나와준게 어딘가 싶었음.
setTimeout(() => {
console.log(error);
},
Number(
getComputedStyle(document.getElementsByClassName('circle')[0])
.transitionDuration[0]) * 1000;);
이제 setTimeout에 시간 파라미터를 넣어주는데
css의 transition-duration : '2s'로 되어있으니 이걸 파싱해서 2000으로 고쳐지게끔 코딩을 해야한다.
그래서 문자열의 [0]번째 요소인 2를 숫자로 형변환을 하고 1000을 곱하여 2000을 만든다.
근데 코드가 보다시피 답도없이 더러워져서, 이걸 변수에 넣기로 했다.
여기서 또 한번 문제가 발생하는데
const time = Number(getComputedStyle(document.getElementsByClassName('circle')[0])
.transitionDuration[0]) * 1000;
btn.addEventListener('click', () => {
showCircle(x, y, rad)
.then(div => {
setTimeout(() => {
div.classList.add('message-ball');
div.append('Hello, world!');
}, time);
})
버튼밖에서 상수를 만들어서 넣어줘서 돌렸더니 정상작동을 하지 않는 것이다.
뭔가 잘못된 것이 무엇일까 고민하고 다시 한번 이번엔 콜백함수의 스코프에 넣어봤다.
btn.addEventListener('click', () => {
const time = Number(getComputedStyle(document.getElementsByClassName('circle')[0])
.transitionDuration[0]) * 1000;
showCircle(x, y, rad)
.then(div => {
setTimeout(() => {
div.classList.add('message-ball');
div.append('Hello, world!');
}, time);
})
근데 이 또한 정상작동인 2초뒤에 문구가 팝업이 실행되지 않는다.
왜 그런가 고민을 했는데 떠올랐다.
querySelector로 나오는 유사 이터럴 객체 NodeList는 실행된 그 순간의 리스트를 정적으로 가지고 있는 반면,
getElement로 접근한 유사 이터럴 객체인 HTMLCollection은 실행될때마다 실시간으로 동적으로 리스트가 바뀐다.
따라서, 변수에 getElements로 넣었다면, 그 위치에 따라서 리스트가 바뀌게 된다는 것이 문제를 일으키는 원인.
btn.addEventListener('click', () => {
showCircle(x, y, rad)
.then(div => {
const time = Number(
getComputedStyle(document.getElementsByClassName('circle')[0])
.transitionDuration[0]) * 1000;
setTimeout(() => {
div.classList.add('message-ball');
div.append('Hello, world!');
}, time);
})
이렇게 then 안에서 상수를 때려버리고 setTimeout에 상수 time을 넣어주면 아주 잘 작동한다.
이짓하느라 진도가 늦어졌네.. 내일 좀 더 자세히 보고 동기/비동기를 다시 포스팅해야지.
'JS' 카테고리의 다른 글
WIL (0) | 2023.02.26 |
---|---|
Closure (0) | 2023.02.22 |
자바스크립트에서의 this (0) | 2023.02.22 |
자바스크립트 데이터타입, 실행컨텍스트 (0) | 2023.02.21 |
자바스크립트 쿼리셀렉터를 for문 돌릴때 생기는 문제 (0) | 2023.02.07 |