● 이론1_ Promise 문법 없이, 데이터 다루기 :
○ 0단계 : json 데이터 출력법 => JSON객체 프로퍼티 메소드 stringify(jsonData,null,들여쓰기 개수?)
# GPT 설명 (근데 중요한건 아니므로, 대략 읽으면서 끄덕 ㄱ)
JSON.stringify(jsonData, null, 2)은 JavaScript에서 객체(jsonData)를 JSON 형식의 문자열로 변환하는 함수인 JSON.stringify를 사용하는 코드입니다.
각 매개변수의 의미는 다음과 같습니다:
- jsonData: JSON 형식으로 변환할 데이터 객체. 예를 들어, { name: "Alice", age: 25 } 같은 객체를 JSON 문자열로 바꿉니다.
- null: replacer 매개변수로, 변환 시 특정 속성만 선택하거나 값을 변환하려면 함수를 전달할 수 있습니다. 여기서 null은 기본 동작(모든 속성을 변환)에 해당합니다.
- 2: space 매개변수로, 출력되는 JSON 문자열의 들여쓰기 수준을 설정합니다. 숫자 2는 각 단계마다 2칸 들여쓰기를 적용합니다. 이는 사람이 읽기 쉽게 포맷팅된 JSON 문자열을 만드는데 유용합니다.
예제
const jsonData = {
name: "Alice",
age: 25,
skills: ["JavaScript", "React"]
};
const jsonString = JSON.stringify(jsonData, null, 2);
console.log(jsonString);
출력:
{
"name": "Alice",
"age": 25,
"skills": [
"JavaScript",
"React"
]
}
요약
- JSON.stringify(jsonData, null, 2)는 jsonData를 JSON 문자열로 변환하며, 사람이 읽기 쉬운 2칸 들여쓰기로 포맷합니다.
- null과 2는 각각 변환 규칙 없음과 들여쓰기 간격을 설정하는 역할을 합니다.
○ 1단계 : 다른 API에서 문자열로 입력된 Json 데이터 불러오기
//API에 저장된 문자열로 입력된 json 데이터라고 가정
const response_2 = `[{ "id": 1, "name": "Jason", "email": "jason@codeitmall.kr", "department": "engineering" }, { "id": 2, "name": "Alice", "email": "alice@codeitmall.kr", "department": "engineering" }, { "id": 3, "name": "Brian", "email": "brian@codeitmall.kr", "department": "marketing" }, { "id": 4, "name": "Erica", "email": "erica@codeitmall.kr", "department": "marketing" }, { "id": 5, "name": "Wilson", "email": "wilson@codeitmall.kr", "department": "sales" }]`;
function getEmployees(callback) {
console.log('Sending request...');
//API에서 json 데이터를 불러오는 과정이 1초정도 걸림 => 비동기 메소드로 구현
setTimeout(() => callback(response_2), 1000);
}
//불러온 데이터를 출력하는 callback 메소드 구현
getEmployees((res)=>{console.log(res)});
○ 2단계 : API로 받은 문자열 json => Parsing 단계를 거쳐, Json 데이터로 변환
//API에 저장된 문자열로 입력된 json 데이터라고 가정
const response_2 = `[{ "id": 1, "name": "Jason", "email": "jason@codeitmall.kr", "department": "engineering" }, { "id": 2, "name": "Alice", "email": "alice@codeitmall.kr", "department": "engineering" }, { "id": 3, "name": "Brian", "email": "brian@codeitmall.kr", "department": "marketing" }, { "id": 4, "name": "Erica", "email": "erica@codeitmall.kr", "department": "marketing" }, { "id": 5, "name": "Wilson", "email": "wilson@codeitmall.kr", "department": "sales" }]`;
function json(strData,callback){
//1_ parsing해서 json변수에 저장
const jsonData = JSON.parse(strData);
//2_ 한번에 처리 가능한 메소드가 아니기 때문에, setTimeout()
//여기서 Parameter : json으로 변환된 Data
setTimeout(()=>callback(jsonData),1000);
}
//변환 후의 json데이터를 하나씩 출력하는 데이터
//즉, response_2의 문자열 => str문자열 데이터로 변환후,
//각 인덱스 하나씩 출력하는 메소드가 된거임
json(response_2,(jsonData)=>{console.log(JSON.stringify(jsonData,null,2))});
//여기서 Argument안에 callback의 Argument는 문자열 data가 아닌 json 데이터 이므로, 따로 저렇게 작성해야함
○ 3단계 : json 데이터를 부서별~회원으로 json 정리 메소드
§전략 : strData => jsonData (Parsing 과정) , jsonData => sortData
const response_2 = `[{ "id": 1, "name": "Jason", "email": "jason@codeitmall.kr", "department": "engineering" }, { "id": 2, "name": "Alice", "email": "alice@codeitmall.kr", "department": "engineering" }, { "id": 3, "name": "Brian", "email": "brian@codeitmall.kr", "department": "marketing" }, { "id": 4, "name": "Erica", "email": "erica@codeitmall.kr", "department": "marketing" }, { "id": 5, "name": "Wilson", "email": "wilson@codeitmall.kr", "department": "sales" }]`;
let json_res_2;
//Parsing 과정
function json(string, callback) {
console.log('Parsing string...');
json_res_2 = JSON.parse(response_2);
setTimeout(() => callback(json_res_2), 1000);
}
json(response_2,(jsonData)=>{console.log(JSON.stringify(jsonData,null,2))})
//Grouping Sort 과정
function groupEmployees(employees, callback) {
console.log('Grouping employees...');
const groupedByDepartment = {}; // 부서별로 그룹화된 데이터를 저장할 객체
employees.forEach((employee) => {
const { name, department } = employee;
// 부서가 아직 객체에 없으면 초기화
if (!groupedByDepartment[department]) {
groupedByDepartment[department] = [];
}
// 해당 부서 배열에 이름 추가
groupedByDepartment[department].push(name);
});
// 1초 후 콜백 호출
setTimeout(() => callback(groupedByDepartment), 1000);
}
//부서별 정리된 Json 출력
groupEmployees(json_res_2,(sort_res_2)=>{console.log(JSON.stringify(sort_res_2,null,2))});
○ 4단계 : 1,2,3단계를 한방에 처리해보기 => 중첩 callBack함수(callBack 지옥)
const response = `[{ "id": 1, "name": "Jason", "email": "jason@codeitmall.kr", "department": "engineering" }, { "id": 2, "name": "Alice", "email": "alice@codeitmall.kr", "department": "engineering" }, { "id": 3, "name": "Brian", "email": "brian@codeitmall.kr", "department": "marketing" }, { "id": 4, "name": "Erica", "email": "erica@codeitmall.kr", "department": "marketing" }, { "id": 5, "name": "Wilson", "email": "wilson@codeitmall.kr", "department": "sales" }]`;
let json_res_2;
//1,2,3단계 함수 구현부
//1단계 API에서 data 불러오기
function getData(callback)
{
//불러왔다 치고,
console.log('Sending request...');
//불러온 data가 strData임
setTimeout(()=>callback(response),1000);
}
//2단계 불러온 strData => jsonData로 parsing
function parsingData(strData,callback){
console.log('Parsing string...');
const jsonData = JSON.parse(strData);
setTimeout(()=>callback(jsonData),1000);
}
//3단계
function groupEmployees(employees, callback) {
console.log('Grouping employees...');
const groupedByDepartment = {}; // 부서별로 그룹화된 데이터를 저장할 객체
employees.forEach((employee) => {
const { name, department } = employee;
// 부서가 아직 객체에 없으면 초기화
if (!groupedByDepartment[department]) {
groupedByDepartment[department] = [];
}
// 해당 부서 배열에 이름 추가
groupedByDepartment[department].push(name);
});
// 1초 후 콜백 호출
setTimeout(() => callback(groupedByDepartment), 1000);
}
//중첩 callBack
getData(()=>json(
response, groupEmployees(jsonData,(sort_data)=>{JSON.stringigy(sort_data,null,2)})
));
○ 중첩 CallBack의 문제점 => 가독성도 ㅈ같고, 디버깅하는데에서도 안좋다고 합디다. => 이러한 것에 대한 대처방안 : Promise 문법 //프로미스나인 생각남
● 이론2_ Promise 객체 정의 :
○ 이론적 정의 :
- 비동기 작업이 완료되면 값을 알려주는 객체 //다시말하면, API에서 불러온 데이터 || 불러온 StrData를 jsonData로 변환된 값 || jsonData를 특정한 기준으로 분류 후, 재완성된 jsonData등의 시간이 어느정도 필요하여, 비동기작업에 대한 반환 데이터를 다루는 객체를 의미함.
- 작업이 완료되면 값을 알려줄 것을 '약속'함
- 먼저, 빈 Promise를 반환 후, 그 Promise객체에 채우겠다는 뜻 //빈 깡통 던져주고, 나중에 사료 채우겠다는 객체
○ Promise 문법 X 비동기 작업 vs Promise 문법 O 비동기 작업 :
- Promise X 비동기 코드 :
function getData(callback)
{
const strData <= 불러온 데이터
setTimeout(()=>callback(strData),1000);
}
function parsing(strData,callback)
{
const jsonData = JSON.parse(strData);
setTimeout((jsonData)=>{callbakc(jsonData)});
}
getData(()=>parsing(strData,
console.log(jsonData)
));
- Promise O 비동기 코드 : { await + fetch()//1단계 } + { await + String 객체 프로퍼티 메소드 json() 메소드//2단계 }
//1단계 : data 불러오기
const strData = await fetch('http://learn.codeit.kr/api/employees');
//2단계 : data Parsing 하기
const jsonData = await strData.json();
//아까와 다르게 string 객체 프로퍼티 메소드 json()메소드 이용
//json의 data 출력
console.log(JSON.stringify(jsonData,null,2));
● 이론3_ Promise 객체 3가지의 상태
- 상태1_ Promise_ Pending 상태 //비동기 작업 진행중 || 미결정인 상태 => 출력 결과
: await 없이 작업만 한 경우의 반환값
Promise {< pending >}
- 상태2_ Promise_ Fulfilled || Rejected 상태 // 비동기 작업 결괏값!
: await 키워드를 붙인 비동기메소드 반환값
◎ 연습문제 :
다음 URL에는 다양한 음식 메뉴가 있습니다(웹 브라우저로 접속해 보세요).
https://learn.codeit.kr/api/menus
fetch() 함수와 await 문법을 사용해서 메뉴 리스트를 가져온 다음 출력하세요.
실습 결과
[
{ type: 'ko', name: '비빔밥' },
{ type: 'ko', name: '삼계탕' },
{ type: 'ko', name: '김치찌개' },
{ type: 'ko', name: '라볶이' },
{ type: 'ch', name: '짜장면' },
{ type: 'ch', name: '탕수육' },
{ type: 'ch', name: '짬뽕' },
{ type: 'jp', name: '라멘' },
{ type: 'jp', name: '스시' },
{ type: 'jp', name: '우동' }
]
- 답 :
// 여기에 코드를 작성하세요.
const strData = await fetch('https://learn.codeit.kr/api/menus');
const jsonData = await strData.json();
console.log(jsonData);
● 이론4_ async 키워드 :
○ 정의 :
await + 비동기작업 메소드 : Promise 객체를 fullfilled || rejected 상태일 때만 반환 되도록 하는 키워드라면, async는 함수 앞에 붙는 키워드로써, 비동기 함수 , 동기 함수가 컴파일러가 왔다갔다 하면서, 원칙적인 작업 순서가 되도록 하는 키워드이다.
○ 예시 코드1 :
const strData = await fetch('https://learn.codeit.kr/api/menus');
const jsonData = await strData.json();
console.log(jsonData);
console.log("1");
console.log("2");
○ 출력 결과:
//비동기 작업 결과이므로, 나중에 출력되는것이 취지에 맞는데,
[
{ type: 'ko', name: '비빔밥' },
{ type: 'ko', name: '삼계탕' },
{ type: 'ko', name: '김치찌개' },
{ type: 'ko', name: '라볶이' },
{ type: 'ch', name: '짜장면' },
{ type: 'ch', name: '탕수육' },
{ type: 'ch', name: '짬뽕' },
{ type: 'jp', name: '라멘' },
{ type: 'jp', name: '스시' },
{ type: 'jp', name: '우동' }
]
//동기 작업 출력 결과
1
2
//시발
○ 예시 코드2 : //예시 코드1의 해결된 코드
async function asyncMethod() {
const strData = await fetch('https://learn.codeit.kr/api/menus');
const jsonData = await strData.json();
console.log(jsonData);
}
asyncMethod();
console.log(1);
console.log(2);
○ 출력 결과:
1
2
[
{ type: 'ko', name: '비빔밥' },
{ type: 'ko', name: '삼계탕' },
{ type: 'ko', name: '김치찌개' },
{ type: 'ko', name: '라볶이' },
{ type: 'ch', name: '짜장면' },
{ type: 'ch', name: '탕수육' },
{ type: 'ch', name: '짬뽕' },
{ type: 'jp', name: '라멘' },
{ type: 'jp', name: '스시' },
{ type: 'jp', name: '우동' }
]
○ async 키워드 관련 규칙 :
- await 키워드 메소드는 main 최상위 js or 외부 js에서는 ★async가 지정된 함수 블록 내에서만 작성 가능
- Arrow_function으로 async 키워드 지정 위치 : () 앞에 붙는다.
const printEmployArrow = async () => {
const strData = await fetch('...');
const jsonData = await strData.json();
console.log(jsonData);
};
● 이론5_ async 상황에서 컴파일러 이동 순서 :
◎ 연습문제2 :
main.js 파일을 실행했을 때 어떤 결과가 출력될까요?
- asyncFunction.js
export async function printEmployees() {
console.log('2');
const response = await fetch('https://learn.codeit.kr/api/employees');
console.log('3');
const data = await response.json();
console.log('4');
}
- main.js
import { printEmployees } from './asyncFunctions.js';
console.log('1');
printEmployees();
console.log('5');
console.log('6');
- 알아야 할 개념 :
=> 컴파일러는 async만 보고 왔다리 갔다리가 아닌, 비동기 함수의 반환 값인 Promise 객체의 상태를 보고 왔다갔다 하는 것이다.
=> 그럼 시발 async 키워드는 왜 있음? : 약간 이정표 느낌 정도인것 같다. //요안에 비동기함수 있으니깐 시발아 Promise 객체 확인하고 가 하는 김부선 느낌임
- 답 :
1
2
5
6
3
4