Javascript에서의 비동기 처리
async는 "asynchronous"의 줄임말로, "비동기"를 의미한다. 프로그래밍에서 async는 비동기 작업을 처리하는 데 사용되는 키워드다. 즉, 어떤 작업을 실행할 때 그 작업이 완료될 때까지 기다리지 않고 다른 작업을 실행할 수 있도록 하는 것을 의미한다.
자바스크립트는 기본적으로 단일 스레드 기반의 언어, 즉 동기식 언어이기 때문에 한 번에 하나의 작업만 처리할 수 있다. JS에서 동기 방식으로 작동하면 이전 작업이 완료될 때까지는 다음 작업을 수행할 수 없다. 병렬 처리와 네트워크 등의 작업을 위해서는 비동기 방식이 필요하다.
.then()방식: Promise 기반async/await방식: Promise를 좀 더 읽기 쉽게 만든 sugar syntax
| 항목 | .then() |
async/await |
| 구조 | 체이닝 (중첩될 수 있음) | 동기 코드처럼 읽힘 |
| 에러 처리 | .catch()로 따로 처리 |
try/catch 블록 사용 |
| 가독성 | 복잡한 흐름일수록 가독성 나빠짐 | 간결하고 명확한 흐름 |
| 중첩 처리 | .then().then()으로 체인 중첩 |
await로 순차적 흐름 표현 |
| 동시 실행 | .then()으로 명시적 분기 가능 |
Promise.all() 같이 별도로 병렬 처리 작성 필요 |
아래 두 코드는 다른 방식을 사용하지만 같은 기능을 한다.
/* then 방식 */
fetch("/api/data")
.then(res => res.json())
.then(data => console.log(data));
/* async/await 방식 */
async function getData() {
const res = await fetch("/api/data");
const data = await res.json();
console.log(data);
}
Node.js + MySQL 연동하기
- MySQL을 설치한다.
- MySQL Workbench (또는 MySQL Shell)에서 다음 쿼리를 입력해 DB와 테이블을 생성한다.
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE USERINFO (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(45) NOT NULL,
username VARCHAR(45) NOT NULL,
password VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);

- 다음 명령어를 입력해 mysql2 모듈을 설치한다:
npm install mysql2 - 서버단에서
db.js파일을 생성한다.
/* server/db.js */
const mysql = require("mysql2");
const connection = mysql.createConnection({
host: "localhost",
user: "host", // 실제 사용자 이름
password: "password", // 실제 비밀번호
database: "database", // 실제 DB 이름
});
const db = connection.promise();
module.exports = db;
index.js상단에 다음 코드를 추가한다:const db = require("./db.js");- 비밀번호 암호화를 위해 bcrypt 모듈을 설치한다:
npm install bcryptjs index.js상단에 다음 코드를 추가한다:import bcrypt from "bcryptjs";
회원가입 기능 구현하기
🔹 클라이언트 사이드
<form class="signup_form">
<h1 class="signup_title">회원가입</h1>
<div class="signup_inputs">
<div class="signup_box">
<input
placeholder="이름"
class="signup_input"
required=""
type="text"
/><i class="ri-account-circle-line"></i>
</div>
<div class="signup_box">
<input
placeholder="ID"
class="signup_input"
required=""
type="text"
/><i class="ri-user-fill"></i>
</div>
<div class="signup_box">
<input
placeholder="비밀번호"
class="signup_input"
required=""
type="password"
/><i class="ri-lock-2-fill"></i>
</div>
<div class="signup_box">
<input
placeholder="비밀번호 재입력"
class="signup_input"
required=""
type="password"
/><i class="ri-lock-2-fill"></i>
</div>
</div>
<button type="submit" class="signup_button">회원가입</button>
<div class="signup_register">
이미 계정이 있으신가요? <a href="/signup">로그인</a>
</div>
</form>
fetch("/api/sign-up", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: name,
username: username,
password: password,
confirmPw: confirmPw,
}),
})
.then((response) =>
response.json().then((data) => ({ status: response.status, data }))
)
.then(({ status, data }) => {
if (status === 201) {
// 회원가입 성공
setUsernameCheck(false);
setPwCheck(false);
alert("회원가입이 완료되었습니다. 로그인 해주세요.");
navigate("/login");
} else if (status == 400) {
// 비밀번호 불일치
setPwCheck(true);
setUsernameCheck(false);
} else if (status == 409) {
// ID 중복
setUsernameCheck(true);
setPwCheck(false);
} else {
setPwCheck(false);
setUsernameCheck(false);
alert("회원가입 중 오류가 발생했습니다. 다시 시도해주세요.");
}
});
🔹 서버 사이드
/* 회원가입 */
app.post("/api/sign-up", (req, res) => {
const { name, username, password, confirmPw } = req.body;
/* 비밀번호 확인 */
if (password !== confirmPw) {
return res.status(400).json({ error: "Invalid password" });
}
/* 중복 아이디 체크 */
db.query("SELECT * FROM USERINFO WHERE username = ?", [username])
.then(([rows]) => {
if (rows.length > 0) {
return res.status(409).json({ error: "Conflict username" });
}
/* 비밀번호 암호화 */
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(password, salt);
/* DB에 회원 정보 추가 */
return db.query(
"INSERT INTO USERINFO (name, username, password) VALUES (?, ?, ?)",
[name, username, hash]
);
})
.then(() => {
if (!res.headersSent) {
res.status(201).json({ message: "User created" });
}
})
.catch((err) => {
console.error("Error occurred on sign-up:", err);
if (!res.headersSent) {
res.status(500).json({ error: "Server error" });
}
});
});

로그인 기능 구현하기
- 로그인 구현을 위해 jwt 모듈을 설치한다:
npm install jsonwebtoken index.js상단에 다음 코드를 추가한다.
const jwt = require("jsonwebtoken");
const SECRET_KEY = "비밀키";
🔹 클라이언트 사이드
<form class="login_form">
<h1 class="login_title">로그인</h1>
<div class="login_inputs">
<div class="login_box">
<input
placeholder="ID"
class="login_input"
required=""
type="text"
/><i class="ri-user-fill"></i>
</div>
<div class="login_box">
<input
placeholder="비밀번호"
class="login_input"
required=""
type="password"
/><i class="ri-lock-2-fill"></i>
</div>
</div>
<button type="submit" class="login_button">로그인</button>
<div class="login_register">
아직 회원이 아니신가요?
<a href="/signup">회원가입</a>
</div>
</form>
fetch("/api/log-in", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: username,
password: password,
}),
})
.then((response) =>
response.json().then((data) => ({ status: response.status, data }))
)
.then(({ status, data }) => {
if (status === 200) {
setLoginCheck(false);
sessionStorage.setItem("username", data.username);
sessionStorage.setItem("token", data.token);
navigate("/");
} else {
setLoginCheck(true);
}
})
.catch((error) => {
console.error("Error occurred on login:", error);
setLoginCheck(true);
});
🔹 서버 사이드
app.post("/api/log-in", (req, res) => {
const { username, password } = req.body;
db.query("SELECT * FROM USERINFO WHERE username = ?", [username])
.then(([rows]) => {
/* 유효하지 않은 ID */
if (rows.length === 0) {
return res.status(401).json({ error: "Invalid ID" });
}
const user = rows[0];
const isPwCorrect = bcrypt.compareSync(password, user.password);
/* 비밀번호가 틀린 경우 */
if (!isPwCorrect) {
return res.status(401).json({ error: "Invalid password" });
}
/* JWT 토큰 생성 */
const payload = { username: username };
const token = generateToken(payload);
return res.status(200)
.json({ message: "Login success", username, token });
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: "Server error" });
});
});

TODO
- 로그인 여부(토큰을 가지고 있는가?)를 전역으로 관리하기
- 로그아웃 구현하기
- 토큰 유효성 검증 구현하기
[참고자료]
async / await 개념 정리 (Feat. 동기, 비동기)
📡 동기와 비동기 동기(synchronous)란, 어떤 작업을 실행할 때 그 작업이 끝나기를 기다리는 방식을 의미한다. 즉, 작업이 완료될 때까지 다음 코드의 실행을 멈추고 기다리는 것이다. 이러한 방식
trustmitt.tistory.com
[MySQL] MySQL 설치하기 (윈도우 / windows)
MySQLMySQL은 가장 많이 사용되는 데이터베이스 중 하나이다.무료이기에 간단히 설치해 바로 사용할 수 있다. 윈도우와 리눅스 등 다양한 운영체제에서 사용 가능해 확장성이 뛰어나다. 표준 SQL
code-angie.tistory.com
MySQL :: 쿼리문, 명령어 모음
MySQL command Cheat Sheet 메모입니다🤓
velog.io
[Node.js] bcrypt 비밀번호 암호화 하기
회원가입을 구현할 때 회원 정보를 데이터베이스에 저장해야하는데 회원의 비밀번호를 평문 그대로 저장하게 된다면? 관리자가 모든 회원의 비밀번호를 알 수 있음 -> 보안 취약점 발생 비밀번
jisilver-k.tistory.com
[Node.js] express 프레임워크와 MySQL을 연동하여 CRUD 구현하기
※ express에 대한 설명은 아래의 링크를 참고 바란다.express 프레임워크로 웹 서버 구축하기간단하게 express 사용하여 웹 서버를 구축해보았다. 하지만 사용자의 데이터를 받어서 데이터베이스에
velog.io
NodeJS (JWT를 이용한 로그인 구현하기)
첫번째 프로젝트를 진행했을 당시, 백엔드를 담당하였고 그 중 User와 Admin 관련 기능을 구현하게 되었다. User 기능 중 가장 기본이 되는 로그인과 로그아웃 방식을 JWT 토큰을 활용한 방식으로 구
velog.io
'Krafton Jungle > 6. Frameworks' 카테고리의 다른 글
| [WEEK14] Day 6 (0) | 2025.06.17 |
|---|---|
| [WEEK14] Day 5 (0) | 2025.06.16 |
| [WEEK14] Day 3 (0) | 2025.06.14 |
| [WEEK14] Day 1 (0) | 2025.06.12 |