working_helen

[JavaScript 기초] JavaScript 응용 본문

외부 수업/React 스터디

[JavaScript 기초] JavaScript 응용

HaeWon_Seo 2024. 1. 14. 23:20

강의명 : 한입 크기로 잘라 먹는 리액트(React.js) - 섹션 2. JavaScript 응용

 

1. Truthy & Falsy

2. 비 구조화 할당

3. Spread

4. 동기/비동기
5. 콜백 함수

  1) 콜백 함수
  2) 콜백 지옥 (Callback Hell)
  3) Promise
  4) async & await
  5) API 호출

 

 


1. Truthy & Falsy

- Falsy에 해당되는 것 : null, undefined, 0, "" (빈 문자열)

- 단락회로 평가 : 논리연산자가 앞에서부터 평가하고, 결과가 결정되면 뒤를 고려하지 않는 특성

- 아래 코드에서 person이 'Falsy'면 바로 'Falsy'로 name 할당, name이 Truthy면 바로 name 값을 리턴

const getName = (person) => {
	const name = person && person.name;
   	return name || "객체가 아닙니다";
};

// name에 Falsy 할당
// -> false에 해당하는 name은 넘어가고, true에 해당하는 "객체가 아닙니다" 리턴
let p1;
let p2 = undefined;
const name1 = getName(p1);
const name2 = getName(p2);

// name에 Truthy 할당 -> name이 리턴
let p3 = "Mark";
const name3 = getName(p3);

 

 

 

2. 비 구조화 할당

- 배열에서

let arr = ['one', 'two', 'three'];
let [one, two, three] = arr;

[one, two, three] = ['one', 'two', 'three'];

[one, two, three] = ['one', 'two'];		//three는 undefined
[one, two, three = 'three'] = ['one', 'two'];	//따로 지정

// 비 구조화 할당을 이용한 배열 원소 swap
let a = 10;
let b = 20;
console.log(a, b);

[a,b] = [b,a];
console.log(a, b);

 

- 객체 정의에서

key 값을 기준으로 할당

let object = {one:'one', two:'two', three:'three'}
let {one, two, three} = object;

// key 값을 기준으로 할당되므로
// 순서에 관계없이 one에는 one이 할당
let {two, three, one} = object;

// one 값을 NewOne이라는 이름의 key에 할당
let {one : NewOne, two, three} = object;

 

 

 

3. Spread

- 객체 혹은 배열에 중복된 원소가 있을 때, 다른 곳에도 동일하게 사용되도록 펼쳐주는 역할

// 모든 쿠키가 동일하게 가지는 원소들
const cookie = {
    base : "cookie",
    madeIn : "Korea"
};

// 하위 쿠키 객체에 spread
const ChocoCookie = {
    ...cookie,
    topping : "chocolate"
};

const blueberryCookie = {
    ...cookie,
    topping : "blueberry"
};
const fruit = ['apple', 'banana'];
const vegetable = ['carrot', 'potato'];

// fruit와 vegetable 배열 spread + 새로운 원소도 추가
const food = [...fruit, ...vegetable, 'meat'];

 

 

 

 

 

4. 동기/비동기

1) 동기 처리 vs 비동기 처리

- 동기 처리 : JS는 코드 작성된 순서에 따라 SingleThread 방식으로 수행, 먼저 시작된 작업을 모두 끝내고 나서야 다음 작업을 수행할 수 있기 때문에 하나의 작업이 너무 오래 걸리면 전체 작업 시간이 길어지는 문제

 

- 비동기 처리 : SingleThread에 어러 개의 작업을 동시에 실행시켜 수행 시간을 단축하는 방식, 현재 실행중인 작업을 지속하며 다른 작업을 병렬적으로 수행, 작업이 끝나는 시점에 콜백 함수를 호출

setTimeout(()=>{} 수행할 함수, 함수 실행까지 기다릴 시간);
setTimeout((a)=>{console.log(a);}, 1000);	// 1000이 1초를 의미
  • SetTimeout()과 콜백함수 cb()는 Call Stack이 아닌 Web APIs에 저장
  • SetTimeout()의 대기 시간이 종료되면, 콜백함수 cb()가 Callback Queue로 이동
  • 콜백함수 cb()는 다시 Call Stackd으로 이동해 함수 실행

 

2) 비동기 작업의 상태

Pending(대기 상태) resolve Fulfilled(성공) 혹은

                                reject Rejected(실패)

 

 

 

 

 

5. 콜백 함수

1) 콜백(Callback) 함수

- 호출하는 함수의 매개변수로 함수 객체 자체를 전달하는 것, 호출 함수 내에서 콜백함수가 실행

- 주로 익명 화살표 함수 형태로 정의하여 사용

- 하나의 콜백함수가 여러 호출 함수에서 사용되는 경우엔 별도로 함수 정의

// 콜백함수를 인자로 전달해서 실행
함수(인자에 콜백함수 cb){
	setTimeout(()=>{cb() 실행}, 시간);
}
// 함수 인자로 resolve + reject시 콜백함수 전달
function isPositive(num, resolve, reject) {
    setTimeout(()=> {
        if(typeof(num) === "number"){
            resolve(num >=0 ? "양수" : "음수");
        } else {
            reject("숫자가 아닙니다");
        }
    }, 2000);
}

num=5; //num=[];
isPositive(num, 
    (res) => {console.log("숫자입니다 : ", res);},
    (err) => {console.log(err);}
);

 

 

 

2) 콜백 지옥 (Callback Hell)

- 함수의 매개변수로 넘겨지는 콜백 함수가 반복되어 코드의 들여쓰기가 매우 깊어지는 현상

- 비동기 호출이 자주 일어나는 코드에서 발생, 코드의 가독성이 떨어지고 수정하기 어려워진다.

출처 : https://velog.io/@seul06/JavaScript-%EC%BD%9C%EB%B0%B1-%EC%A7%80%EC%98%A5

 

 

 

3) Promise

(MDN) 프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있습니다. 다만 최종 결과를 반환하지는 않고, 대신 프로미스를 반환해서 미래의 어떤 시점에 결과를 제공합니다.

 

- Promise 객체를 return 하는 방식으로 콜백 지옥을 탈출할 수 있다.

- 비동기 처리의 결과를 객체에 저장해서 활용할 수 있게 해준다.

- Promise를 반환하는 함수 = 비동기 처리되는 함수

- Promise 객체에 then/catch method를 적용해 콜백함수 수행

  • Promise.then : resolve를 실행했을때 결과값을 파라미터로 받아서 콜백함수 수행
  • Promise.catch : reject를 실행했을때 결과값을 파라미터로 받아서 콜백함수 수행
function isPositiveP(num){

// resolve, reject 콜백 함수를 받아서 수행할 내용
    const executor = (resolve, reject) => {
        setTimeout(()=> {
            if(typeof(num) === "number"){
                resolve(num >=0 ? "양수" : "음수");
            } else {
                reject("숫자가 아닙니다");
            }
        }, 2000);
    };  

// 위의 결과값을 Promise 객체로 리턴
    const asyncTask = new Promise(executor);
    return asyncTask;
}


const res = isPositiveP([]);
res
    .then((res) => {
        console.log("숫자입니다 : ", res);	// resolve 콜백함수 수행
    })
    .catch((err) => {
        console.log(err);			// reject 콜백함수 수행
    });

 

 

- Promise로 콜백 함수 코드 개선하기

function taskA(a, b, cb){
    setTimeout(()=>{
        const res = a+b;
        cb(res);
    }, 1000);
}

function taskB(a, cb){
    setTimeout(()=>{
        const res = a*2;
        cb(res);
    }, 2000);
}

function taskC(a, cb){
    setTimeout(()=>{
        const res = a*(-1);
        cb(res);
    }, 1000);
}

taskA(3, 4, (a_res)=>{
    console.log("taskA : ", a_res);		// taskA의 콜백함수
    taskB(a_res, (b_res)=>{
        console.log("taskB: ", b_res);		//taskB의 콜백함수
        taskC(b_res, (c_res)=>{
            console.log("taskC: ", c_res);	//taskC의 콜백함수
        })
    })
});

// cb()를 따로 받지 않고, 바로 resolve나 reject 실행
function taskA(a, b){
    const executor = (resolve, reject) =>{
        setTimeout(()=>{
            const res = a+b;
            resolve(res);
        }, 1000);
    };

    const asyncTask = new Promise(executor);
    return asyncTask;
}


// executor 객체 생성 과정을 Promise에 바로 입력
function taskB(a){
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            const res = a*2;
            resolve(res);
        }, 2000);
    });
}

function taskC(a){
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            const res = a*(-1);
            resolve(res);
        }, 1000); 
    });
}



taskA(5, 1).then((a_res)=>{
    console.log("taskA: ", a_res);
    return taskB(a_res);        // 콜백함수를 실행, Promise 객체를 리턴
}).then((b_res)=>{              // 리턴된 Promise 객체를 바로 이어서 이용
    console.log("taskB: ", b_res);
    return taskC(b_res);
}).then((c_res)=>{
    console.log("taskC: ", c_res);
})

 

※ Promise Hell

: 지나친 then method 남용으로 코드가 길어지는 것

Promise를 이용한 비동기 처리의 가독성을 높이기 위해 async & await 활용 

 

 

 

 

4) async & await

① async

- Promise를 리턴하는 비동기 처리 함수로 지정, 리턴값이 Promise 객체

- 내부에 await 함수를 사용할 수 있게 처리한다.

 

② await

- 비동기 함수 앞에 붙여 비동기 함수가 동기 함수처럼 작동하게 만듬

- 비동기 함수에 await를 붙히면 함수의 수행이 완료되기 전까지 다음 코드를 실행하지 않는다.

- async가 붙은 함수 내에서만 사용될 수 있다.

 

(예제 1)

- 비동기 처리 함수 hello()는 Promise 객체를 리턴

- await hello()는 Promise 객체의 resolve() method 실행 결과를 리턴

async function hello() {
    return "hello Async";
}

// Promise 객체 리턴
console.log(hello());		//A

// Promise 객체에 콜백함수 수행
hello().then((res)=>{
    console.log(res);		//B
});

// asymc 함수 내에서 awiat로 실행
async function main() {
    const result = hello();		//C
    console.log(result);
    const result2 = await hello();
    console.log(result2);		//D
}
main();

 

(예제 2)

// Promise 객체 반환 비동기 함수
function delay(ms) {
    return new Promise(resolve => {
        console.log(`${ms}초 시작`);
        setTimeout(() => {
        console.log(`${ms}초 종료`);
        resolve()
        }, ms);
    });
}

async function main() {
    delay(1000);		//A
    delay(2000);		//B
    const result = Promise.resolve();	//C
    console.log(result);
  }
main();

- 비동기 처리되는 A, B, C 코드 순서대로 실행

- 그로 인해 1초와 2초가 다 지나기 전에 C 함수 실행됨

async function main() {
    await delay(1000);		//A
    await delay(2000);		//B
    const result = Promise.resolve();	//C
    console.log(result);
  }
main();

- A와 B가 동기 처리 되었기 때문에 1초, 2초가 다 지난 후에 다음 함수 실행

async function main() {
    delay(1000);		//A
    await delay(2000);		//B
    const result = await Promise.resolve("종료");	//C
    console.log(result);
  }
main();

- A는 비동기 함수이므로 1초가 다 지나기 전에 B 실행

- B는 동기 처리되었으므로 B가 다 끝난 다음에 C 실행

- await Promise.resolve() : Promise 객체를 resolve에 수행한 결과로 리턴

 

 

5) API 호출

출처 :  한입 크기로 잘라 먹는 리액트(React.js) - 섹션 2. JavaScript 응용, API 호출하기 강의

 

- API의 개념 : 2023.07.04 - [TAVE/뿌스팅 프로젝트] - [데이터 수집] API의 개념 / XML 형태 처리

- API에 접근해서 데이터를 얻고, json 형태로 변환하는 비동기 처리 함수 정의 

async function getData(){
    let rwaResponse = await fetch("API 주소");
    let jsonResponse = await rwaResponse.json();
}
getData();

 

 

 

 

 

 

 

 

Reference

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98
https://velog.io/@seul06/JavaScript-%EC%BD%9C%EB%B0%B1-%EC%A7%80%EC%98%A5
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await