티스토리 뷰

2024.12.18 - [웹 개발 공부하기] - [12.18] 결제(주문)하기 API 구현해보기🤔

 

어제 했던 결제(주문)API 에서 문제가 발생했다!

테스트하면서 이전에 테스트한 conn.query는 주석으로 바꿔놓고 테스트를 했었다.

그래서 주석을 다 풀고 한 번 포스트맨을 돌려봤더니...

400 Bad Request가 떴다...

그리고 워크벤치를 확인해봤더니.. delivery 테이블의 데이터만 잘 들어간 걸 확인할 수 있었다.

let delivery_id;
let order_id;

let sql = `INSERT INTO delivery (address, receiver, contact) VALUES (?, ?, ?)`;

let values = [delivery.address, delivery.receiver, delivery.contact];
conn.query(sql, values,
    (err, results) => {
        if(err) {
            console.log(err);
            return res.status(StatusCodes.BAD_REQUEST).end();
        }

        delivery_id = results.insertId;
        console.log("results.insertId : ",results.insertId);
        console.log("conn.query - delivery_id : ",delivery_id);
})

console.log("out - delivery_id : ", delivery_id);

sql = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id)
        VALUES (?, ?, ?, ?, ?)`;
values = [firstBookTitle, totalQuantity, totalPrice, userId, delivery_id];
conn.query(sql, values,
    (err, results) => {
        if(err) {
            console.log(err);
            return res.status(StatusCodes.BAD_REQUEST).end();
        }

        order_id = results.insertId;
})

혹시나해서 console.log를 찍어서 어떤 것 때문에 이런 일이 생기나 하고 확인하기로 했다.

띠용?

results.insertId 가 먼저고 그 다음이 conn.query - delivery_id 그 다음이 out - delivery_id 순서인데..

왜 갑자기 out - delivery_id 니가 먼저 나타나서 undefined 로 데이터를 뿌리냐 🤷‍♀️

이게 웬일이고 하니.......

 

Node.js의 논 블로킹 I/O 특징 때문이다.

논 블로킹 I/O의 특징은 한 명이 일을 하는데, 요리를 순차적으로 하는 것이 아니라, 중간에 비는 시간이 있으면 다른 요리를 한다.

라면 1개 / 볶음밥 이 있다고 치자. 라면 1개는 조리시간이 10분이고 5분은 물이 끓는데까지 걸리는 시간이다.

볶음밥은 5분이면 완성한다. 라면이 먼저고 그 다음이 볶음밥이라면 물 끓는 5분동안 요리사가 노느냐?

아니다. 그 시간동안 볶음밥을 만드는 거다.

즉, 노는 시간 없이 최대한 효율적으로 사용하려고 다른 요리를 한다는 것이다.

이 특징 때문에 생긴 일이다...

 


💥 Node.js 비동기 처리 방식

 - 비동기 발생(이전 시간이 오래 걸리면 기다리지않고 다음 코드를 무작정 실행함)

실행되는 코드가 기다려야 하는 시간이 생긴다는 의미

ex. setTimeOut(), setInterval, query()

 

 - 비동기 처리(순서를 맞춰서 코드를 실행해주겠다! = 이전 시간이 오래 걸려도 기다려줌)

1. 콜백함수 : 할 일 다 하고 이거 실행해줘 (= 순서 맞춰서 이걸 뒤에 실행해줘)

2. promise(resolve, reject)

3. then & catch

4. async & await

 

query( ) ? 그거 시간걸리잖아; 어어 하고있어~ 나 일단 그 다음 코드 먼저 읽을게~ 🏃‍♀️🏃‍♂️

이렇게 된 것이다 ^ㅁ^ ...

그래서 비동기 처리에 가장 많이 사용되는 async & await를 알아보려 한다.

async & await를 알아보기 위해선.. promise를 어느정도 이해해야 하기 때문에 promise 부터 알아보고 가자😀

 


 

💥 promise 객체

Promise는 무조건 약속을 지키는 "객체" 이다.

매개변수로 함수를 받고, 일을 다 하면 무조건 콜백함수 resolve() 또는 reject() 하나를 호출한다.

성공하면 resolve(결과값) 실패하면 reject(에러값) 이다.

간단한 코드로 보자면,

let promise = new Promise(function(resolve, reject) {
    setTimeout(() => resolve("완료!"), 3000);
});

3초 후, 성공을 했단 뜻으로 "완료!"를 나타내달라는 것이다.

보면 3초 후에 끝나는 걸 볼 수 있다.

그럼 성공했단 뜻인데... "완료!" 라는 걸 본 적이 없다...

promise의 짝꿍이 존재한다.

promise한테 일을 시켰을 때 일을 다하면 나한테 말해! 라고 하는 애다.

 

promise.then() 이다. promise의 기본 메소드다. promise.then( ____, ____ ) 이렇게 사용이된다.

빈 공간 둘 다 콜백함수를 전달시킬거고, 성공을 하면 앞의 공백, 실패를 하면 뒤의 공백이다.

let promise = new Promise(function(resolve, reject) {
    setTimeout(() => resolve("완료!"), 3000);
}); 

promise.then(function(result){console.log(result)}, function(error){});

이렇게 된다면, promise 너 일 다 했어? 성공했네? console로 result값 뿌려줄게!

아까와는 다르게 resolve의 결과값을 뿌려주는 걸 볼 수 있다.

 

그럼, 결제 API는 INSERT가 3번이니까 비동기 처리를 한 번 더 할 수 있게끔 해보겠다.

여러개의 promise의 순서를 지켜준다 해서 promise에 chain을 건다 라고 한다.

즉, promise chaining 이다.

let promise = new Promise(function(resolve, reject) {
    setTimeout(() => resolve("완료"), 3000);
}).then(
    function(result){
        console.log(result);
        return result + "!!!!!"
    },
    function(error){}
).then(
    function(result){
        console.log(result);
        return result + "!!!!!"
    },
    function(error){}
).then(
    function(result){
        console.log(result);
    },
    function(error){}
);

로직은 이렇게 짰다.

promise를 잇는 것보단 then이 이어지고 이어지는 것이다.

콘솔창을 보니 3초 후, 완료가 나오고 그 다음에 !!!!! 이 추가된 완료!!!!! 가 나오고 그 다음은 !!!!! 이 더 추가된 완료!!!!!!!!!가 나왔다.

말 그대로 result를 콘솔창에 찍고 return을 통해 result값에 !!!!!이 추가된 값을 다음 then에게 넘겨준다.

성공을 했기 때문에 2번째 then에서도 성공 함수가 실행된다. 3번째 then에서도 똑같이 성공 함수가 실행되는 것이다.

 

사실 이대로 promise를 사용해도 되긴 하지만, 요즘 트렌드에 맞는 async&await도 알아보려한다.

지금 프로젝트 말고 토이프로젝트를 준비했을 때, 챗 gpt가 async&await을 넣어서 로직을 짜준 적이 있었다.

그 땐, 이게 뭐지 😑 하고 이해를 못해서 해당 로직을 안 쓰고 다른 로직을 짜서 썼던 적이 있다.

만약 promise가 더 좋은 처리방식이라면 챗 gpt도 promise로 쓰지 않았을까?

promise보다 더 늦게 나온 게 async&await 이라는데 그럼.. promise의 단점을 보완한 것 아닐까? 싶다

그러니 async&await도 한 번 알아보자😦

 


 

💥 async&await 

async function f() {
    return 7;
};

f().then(
    function(result){
        console.log("promise resolve : ", result);
    },
    function(error){
        console.log("promise reject : ", error);
    }
);

async는 이런 식으로 사용이 된다.

일반 함수인 function f() {} 앞에 async 를 붙여주면 된다. 그 이후, 함수 f() 뒤에 .then을 붙여서 사용한다.

이렇게되면 어느 값이 콘솔에 찍히는 지 한 번 먼저 보겠다.

오잉? 내가 resolve인지 reject인지도 안 줬는데 냅다 resolve 를 console에 띄워주네?

 

맞다! 사실 async 함수는 무조건 promise 객체를 반환한다.

만약에 반환값이 promise가 아니라면 Promise.resolve()로 감싼다.

즉, return 7 이 아니라 return Promise.resolve(7); 이 되는 것이다.

그래서 resolve 값이 콘솔에 찍히게 되는 것이다.

 

그럼 await은 뭐지?

async function f() {
    let promise = new Promise(function(resolve, reject) {
        setTimeout(() => resolve("완료!"), 3000);
    });

    let result = await promise;
    console.log(result);
};

f();

await은 async 안에서만 활동이 가능하다.

promise 객체 알아볼 때 썼던 로직을 그대로 갖고와서 async 안에 넣고,

await promise; 써주었다.

그 다음 f() 함수를 호출해준다. 그럼 콘솔에 어떻게 찍히는 지 보자.

promise객체 실행했을 때와 똑같은 값이 나왔다. 그것도 3초 후에!

자세히 보니, then이 없다. 근데도 잘 실행이 되는 것이다.

말 그대로, await은 promise 객체가 일을 다 할 때까지 기다려주는 것이다.

promise가 일을 다 할 때까지 기다려준 후에 할 일을 한다.

이렇게 async&await을 사용하게되면 좀 복잡해보였던 then() 을 쓸 이유가 없어지는 것이다.

 

즉, promise만 사용할 때보다 코드가 간편해지고 편리하게 사용이 가능하다는 것이다.

그래서 promise보단 async&await을 쓰는 사람이 많아졌다.

그럼, 이것도 promise 처럼 chaining이 가능할까?

async function f() {
    let promise1 = new Promise(function(resolve, reject) {
        setTimeout(() => resolve("첫번째 쿼리!"), 3000);
    });

    let result1 = await promise1;
    console.log(result1);

    let promise2 = new Promise(function(resolve, reject) {
        setTimeout(() => resolve("두번째 쿼리 with "+ result1), 3000);
    });

    let result2 = await promise2;
    console.log(result2);


    let promise3 = new Promise(function(resolve, reject) {
        setTimeout(() => resolve("세번째 쿼리 with "+ result2), 3000);
    });

    let result3 = await promise3;
    console.log(result3);
};

f();

이렇게 promise 처럼 이어서도 가능하다.

로직을 이렇게 짰다면, promise1을 await이 기다렸다가 result1 값을 콘솔에 찍어주고,

promise2를 기다렸다가 result2값을 콘솔에 찍어주고, promise3을 기다렸다가 result3값을 콘솔에 찍어줄 것이다.

예상한 대로 값이 잘 나오는 걸 볼 수 있다.

3초씩 기다렸다가 값이 나오기 때문에 총 9초가 소요된 것도 볼 수 있다.

이 로직을 이용해서 결제하기 API의 INSERT 문제가 생긴 걸 고칠 수 있을 것 같다👍

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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 31
글 보관함