본문 바로가기
Javascript

자바스크립트 공부4 - 비동기 처리

by 겨니2 2025. 5. 29.

Promise

미래의 작업을 예약하고 결과(성공 여부)에 따라 콜백을 실행할 수 있는 자바스크립트 기능입니다.

then, catch, finally 메서드를 사용하여 처리 흐름을 관리합니다.

Promise의 가장 유용한 기능 중 하나는 일부 데이터(외부 서비스/API)를 불러와 해결할 수 있다는 것입니다.

기존 콜백 패턴

const temperatures = [10, 5, 3];

sumTemperatures(temperatures, value => {
    console.log(value); // 18 (the sum of temperatures)
});

Promise로 리팩토링

const temperatures = [10, 5, 3];

sumTemperatures(temperatures).then(value => {
    console.log(value); // 18 (the sum of temperatures)
});

함수 예시

wait 함수 생성
const wait = milliseconds => {
    // this function returns a new promise
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, milliseconds);
    });
}

new Promise를

사용해야 하는 경우: 직접 비동기 작업을 처리하는 함수를 작성할 때

사용하지 않아도 되는 경우: 이미 비동기 작업을 처리하는 함수나 라이브러리가 Promise를 반환할 때

사용방법
wait(1_000).then(() => {
    console.log("waited 1 second");
});

 

Promise 에는 3가지 상태가 있을 수 있습니다.

  • pending: 아직 완료되지 않았습니다.
  • fulfilled: 성공적으로 완료되었습니다.
  • rejected: 작업이 실패했습니다.

성공적으로 완료되었을 때 미래의 어느 시점에서 콜백을 실행할 수 있습니다.

const promise = new Promise((resolve, reject) => {
    // 비동기 작업을 수행합니다.
    setTimeout(() => {
        const success = true; // 실제 비동기 작업의 결과에 따라 변경될 수 있습니다.
        if (success) {
            resolve("작업 성공");
        } else {
            reject("작업 실패");
        }
    }, 1000);
});

promise
    .then(result => {
        console.log(result); // "작업 성공"
    })
    .catch(error => {
        console.log(error); // "작업 실패"
    });

 

오류처리

sumTemperatures(temperatures)
    .then(value => {
        console.log(value); // 18 (the sum of temperatures)
    })
    .catch(reason => {
        // this callback will run when there's an error
        console.error(reason);
    });

catch를 이용해서 오류를 체크합니다.

finally

getWeatherIn("Amsterdam")
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error(error);
    })
    .finally(() => {
        console.log("Done fetching weather");
    });

성공적으로 완료되고 나면 실행 될 코드를 finally에 작성합니다.

수동으로 거부

getWeatherIn("Amsterdam")
    .then(data => {
        throw new Error("Stopped.");
        console.log(data);
        console.log("Done fetching weather");
    })
    .catch(error => {
        console.error(error);
        console.log("Done fetching weather");
    });

throw new Error는 명시적으로 오류를 발생시킬 수 있습니다.

함수 내부에서 예외 상황을 처리할 때 유용합니다.

async/await

async/await 은 Promise를 더 쉽게 사용할 수 있도록 하는 문법 설택입니다.

async 함수는 항상 Promise를 반환하고, await은 Promise가 해결될 때까지 기다립니다.

async function asyncFunction() {
    try {
        const result = await new Promise((resolve, reject) => {
            setTimeout(() => {
                const success = true; // 실제 비동기 작업의 결과에 따라 변경될 수 있습니다.
                if (success) {
                    resolve("작업 성공");
                } else {
                    reject("작업 실패");
                }
            }, 1000);
        });
        console.log(result); // "작업 성공"
    } catch (error) {
        console.log(error); // "작업 실패"
    }
}

asyncFunction();

fetch()를 이용한 데이터 요청

JSON

대부분의 API는 JSON(Javascript Object Notation)이라는 공통 언어로 통신합니다. 가벼워서 웹에서 일반적으로 사용됩니다.

Javascript에서 JSON을 가장 자주 사용하는 사례는 JSON 문자열을 JSON 객체로 변환하거나 그 반대로 변환하는 것입니다.

JSON의 가장 큰 장점은 통신하려는 API가 어떤 프로그래밍 언어로 작성되었는지는 중요하지 않고 JSON을 읽고 받을 수만 있다면 서로 통신할 수 있습니다. 웹 개발자의 경우 99% JSON을 사용하여 작업하게 됩니다.

JSON 객체의 예
{
    "firstName": "Jane",
    "lastName": "Kwon",
    "age": 35
}

 

JSON 문자열을 JSON 객체로, 또는 그 반대로 변환해야 하는 경우가 많습니다.

JSON.parse(문자열) -> 객체로 변환
const string = '{"firstName":"Jane","lastName":"Kwon","age": 35}';
const person = JSON.parse(string); // {firstName: "Jane", lastName: "Kwon", age: 35}
console.log(person.firstName); // "Jane"
JSON.stringify(객체) -> 문자열 변환
const person = {
    firstName: "Jane",
    lastName: "Kwon",
    age: 35
};
const string = JSON.stringify(person);
console.log(string); //'{"firstName":"Jane","lastName":"Kwon","age":35}'
JSON.stringify(객체) -> 문자열 변환 예시
const prepareStatus = (status, location) => {
    const userId = 42;
    const data = {
        userId,
        status,
        location
    };
    return JSON.stringify(data);
};

console.log(prepareStatus("Delicious food!", "Restaurant"));
// '{"userId":42,"status":"Delicious food!","location":"Restaurant"}'

console.log(prepareStatus("Tasty and fresh!", "Food Market"));
// '{"userId":42,"status":"Tasty and fresh!","location":"Food Market"}'

fetch()

fetch 요청은 네트워크를 통해 전송되어야 하므로 평균적으로 몇 밀리초에서 1초 정도 걸릴 수 있습니다.

이는 서버의 응답 시간, 네트워크 상태, 요청의 복잡성에 따라 달라질 수 있습니다.

// 리팩토링 전
fetch(URL)
    .then(response => {
        return response.json();
    });
    
 
// 화사표 함수 사용 리팩토링 후
fetch(URL)
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });

오류 처리

오류 상태 코드
  • 100-199(또는 1xx): 정보 제공을 위한 응답
  • 200-299(또는 2xx): 성공적인 응답
  • 300-399(또는 3xx): 리디렉션을 위한 것
  • 400-499(또는 4xx): 클라이언트 오류  ex) 404 Not Found - 존재하지 않는 URL / 401 - 권한 없음
  • 500-599(또는 5xx): 서버 오류 ex) 500 - 내부 서버 오류 / 504 - 게이트웨이 시간 초과, 트래픽 초과

대부분의 API의 경우 응답이 성공했는지 확인할 때 response.ok를 체크합니다. 

fetch(URL)
    .then(response => {
        if (!response.ok) {
            // 4xx or 5xx error
            throw new Error("API issues.");
        }
        return response.json();
    })
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error(error);
    });
  • GET: 데이터 읽기
  • POST: 데이터 생성
  • PUT: 데이터 업데이트
  • DELETE: 데이터 삭제
  • 사용자 목록 GET /users
  • 사용자 POST 생성 /users
  • 특정 사용자 PUT 업데이트 /users/{id}
  • 특정 사용자 삭제 DELETE /users/{id}

fetch는 기본적으로 GET으로 설정됩니다.

fetch(URL, {
    method: "GET" // or "get"
})
    .then(response => response.json())
    .then(data => {
        console.log(data);
    });
POST
fetch("https://example.com/api/tweets", {
    method: "POST",
    body: JSON.stringify({
        messege: "Your messege here..."
    })
})
.then(response => response.json())
.then(data => {
    console.log(data); // read the server response
});
PUT
const updateUserName = (firstName, lastName) => {
    // TODO
    return fetch("URL", {
        method: "PUT",
        body: JSON.stringify({
            firstName: firstName, 
            lastName: lastName
            })
    }).then(response => response.json())
    .then(data=> {console.log(data.user.firstName, data.user.lastName)})

}
DELETE
fetch('https://api.example.com/items/123', {
  method: 'DELETE',
})
.then(response => {
  if (!response.ok) {
    throw new Error('삭제 실패');
  }
  return response.text(); // 또는 response.json()
})
.then(data => {
  console.log('삭제 성공:', data);
})
.catch(error => {
  console.error('에러 발생:', error);
});