버튼을 누르면 2초 뒤 DOM이 조작되어 브라우저에 렌더링 된다.
0. HTML 뼈대 및 정리 안된 코드
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>들여쓰기 제거</title>
</head>
<body>
<h1>분식점</h1>
<button>음식제작</button>
<h2 id="log"></h2>
<script>
function orderFood(el, orderList) {
if (el) {
if (Array.isArray(orderList)) {
el.addEventListener('click', () => {
setTimeout(() => {
for (let i = 0; i < orderList.length; i++) {
document.querySelector(
'#log'
).innerHTML += `${orderList[i]}이 완료되었습니다. <br />`
}
}, 2000)
})
}
}
}
orderFood(document.querySelector('button'), ['제육덮밥', '라면'])
</script>
</body>
</html>
- 한 껏 늘려쓴 코드이다.
- if문이 중첩되어있고, 모든 기능들이 함수 하나에 전부 내장되어 있다.
1. if 합치기
<script>
function orderFood(el, orderList) {
if (el && Array.isArray(orderList)) {
el.addEventListener('click', () => {
setTimeout(() => {
for (let i = 0; i < orderList.length; i++) {
document.querySelector(
'#log'
).innerHTML += `${orderList[i]}이 완료되었습니다. <br />`
}
}, 2000)
})
}
}
orderFood(document.querySelector('button'), ['제육덮밥', '라면'])
</script>
- if문이 2개라면 연산자로 묶어서 하나로 표현해줄 수 있다.
- 이를 통해 코드 한 줄을 줄일 수 있고, 들여쓰기를 삭제해줄 수 있다.
1-1. if문 밖으로 코드 빼기 (+ 드모르간의 법칙)
<script>
function orderFood(el, orderList) {
if (!el || !Array.isArray(orderList)) return
el.addEventListener('click', () => {
setTimeout(() => {
for (let i = 0; i < orderList.length; i++) {
document.querySelector(
'#log'
).innerHTML += `${orderList[i]}이 완료되었습니다. <br />`
}
}, 2000)
})
}
orderFood(document.querySelector('button'), ['제육덮밥', '라면'])
</script>
- 논리 연산에서 AND와 OR 연산을 서로 바꾸고 각 변수에 부정을 취할 때 두 값은 논리적으로 같다는 것이 드모르간의 법칙이다.
('el이 존재하며 orderList가 배열로 존재해야 한다'와 'el이 없거나 orderList가 없어야 한다'는 논리적 동치관계) - 여기에서는 드 모르간의 법칙을 도입함으로써 if문 내부에 속한 코드를 밖으로 뺼 수 있었다.
2. 함수 분리(이벤트핸들러 분리)
<script>
function orderFood(el, orderList) {
const buttonClickHandler = () => {
setTimeout(() => {
for (let i = 0; i < orderList.length; i++) {
document.querySelector(
'#log'
).innerHTML += `${orderList[i]}이 완료되었습니다. <br />`
}
}, 2000)
}
if (!el || !Array.isArray(orderList)) return
el.addEventListener('click', buttonClickHandler)
}
orderFood(document.querySelector('button'), ['제육덮밥', '라면'])
</script>
- addEventListener에 속한 이벤트 핸들러를 분리할 수 있다.
- 이를 통해 addEventListener가 click 이벤트를 받았을 경우, 어떤 함수가 실행되었는지 명시적으로 알 수 있게 된다.
2-1. setTimeout 함수를 Promise로 치환해보기
<script>
function orderFood(el, orderList) {
const delay = (time) => new Promise((resolve, reject) => setTimeout(() => resolve(), time))
const buttonClickHandler = async () => {
const delayTime = 2000
await delay(delayTime)
for (let i = 0; i < orderList.length; i++) {
document.querySelector(
'#log'
).innerHTML += `${orderList[i]}이 완료되었습니다. <br />`
}
}
if (!el || !Array.isArray(orderList)) return
el.addEventListener('click', buttonClickHandler)
}
orderFood(document.querySelector('button'), ['제육덮밥', '라면'])
</script>
- setTimeout을 Promise로 치환할 수 있다.
- buttonClickHandler를 async를 이용하여 비동기 함수로 만든다.
- delay라는 Promise를 만든다. 이 promise는 무조건 성공하며, time으로 받은 ms 뒤에 resolve()를 실행할 것이다.
- delay를 buttonClickHandler에 추가한 뒤 await를 걸어주어 함수 내부에서 동기적으로 작업을 수행하게 만든다.
3. 기타 코드 정리
<script>
const logEl = document.querySelector('#log')
const delay = (time) => new Promise((resolve, reject) => setTimeout(() => resolve(), time))
const orderMsg = (order) => logEl.innerHTML += `${order}이 완료되었습니다. <br />`
const buttonClickHandler = async (orderList) => {
const delayTime = 2000
await delay(delayTime)
orderList.forEach(orderMsg)
}
function orderFood(el, orderList) {
if (!el || !Array.isArray(orderList)) return
el.addEventListener('click', () => buttonClickHandler(orderList))
}
orderFood(document.querySelector('button'), ['제육덮밥', '라면'])
</script>
- 가독성을 위해 콜백함수를 분리했다.
- 실행조건을 명시적으로 하기 위해서 변수로 분리할 수 있는 조건은 분리했다.
- 정답은 없다.
'Javascript' 카테고리의 다른 글
클래스) 클래스 필드와 프라이빗 필드 (0) | 2023.03.19 |
---|---|
자바스크립트 함수 주석 (기본기능) (0) | 2023.03.10 |
클린코드 연습 (1) - 배열 고차함수 (0) | 2023.02.04 |
객체 장난 (0) | 2023.02.01 |
n x n 좌표 생성기 (2) / (클로저) (0) | 2023.01.29 |