[포스코x코딩온] 웹개발자 풀스택 과정 5주차 | 비동기 처리

구준희·2023년 7월 31일
0

[포스코x코딩온]교육

목록 보기
12/40
post-thumbnail
post-custom-banner

비동기처리

setTimeout()

setTimeout(code, delay);

  • delay동안 기다리다가 code 함수를 실행
console.log(1);
setTimeout(function(){
  console.log(2);
}, 2000);
console.log(3);

//결과
1
3
2
// 1-2-3이 아닌 1-3-2로 출력된다.

비동기처리란?

  • 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성

왜 비동기 처리일까?

  • 서버로 데이터를 요청 시, 서버가 언제 그 요청에 대한 응답을 줄지도 모르는데 마냥 다른코드의 실행을 안 하고 기다릴 수 없기 때문에

  • 비동기 처리가 아닌 동기 처리면 코드를 실행 -> 기다림 -> 실행 -> 기다림을 반복하게 되면 너무 오래걸림

아래 코드에서의 문제점은?

function goMart(){
  console.log('마트에 가서 어떤 음료를 살지 고민한다.')
}

function pickDrink(){
  setTimeout(function(){
    console.log('고민 끝!!');
    product = '제로 콜라';
    price = 2000;
  }, 3000);
}

function pay(product, price){
  console.log(`상품명: ${product}, 가격 : ${price}`);
}

let product;
let price;
goMart();
pickDrink();
pay(product, price);

callback 함수를 준다.

function goMart(){
  console.log('마트에 가서 어떤 음료를 살지 고민한다.')
}

function pickDrink(callback){
  setTimeout(function(){
    console.log('고민 끝!!');
    product = '제로 콜라';
    price = 2000;
    callback(product, price);
  }, 3000);
}
// function pay(product, price){
//   console.log(`상품명: ${product}, 가격 : ${price}`);
// }
let product;
let price;
goMart();
pickDrink(function(product,price){
  console.log(`상품명: ${product}, 가격 : ${price}`);
});
// pay(product, price);

콜백(callback) 함수

  • Javascript는 함수를 인자로 받고 다른 함수를 통해 반환될 수 있는데, 인자(매개변수)로 대입되는 함수를 콜백함수라고 한다.
  • 즉, 다른 함수가 실행을 끝낸 뒤 실행되는 함수
  • 함수를 선언할 때는 parameter(인자, 매개변수)로 함수를 받아서 쓸수 있다.
  • Q. 콜백함수를 사용하는 이유는?

    A. 비동기 방식으로 작성된 함수를 동기 처리하기 위하여
    • 독립적으로 수행되는 작업도 있는 반면 응답을 받은 이후 처리되어야 하는 종속적인 작업도 있을 수 있으므로 그에 대한 대응 방법이 필요
  • 콜백함수는 보통 함수를 선언한 뒤에 함수타입 파라미터를 맨 마지막에 하나 더 선언해 주는 방식으로 정의

Promise

  • 비동기 함수를 동기 처리하기 위해 만들어진 객체
  • 성공실패를 분리하여 반환
  • 비동기 작업이 완료된 이후에 다음 작업을 연결시켜 진행할 수 있는 기능을 가짐

Promise의 상태

  • pending(대기) : Promise를 수행중인 상태
  • Fulfilled(이행) : Promise가 Resolve된 상태(성공)
  • Rejected(거부) : Promise가 지켜지지 못한 상태. Reject 된 상태(실패)
  • Settled : fulfilled 혹은 rejected로 결론이 난 상태

Promise 사용법

function promise1(flag){
  return new Promise(function (resolve, reject){
    if(flag){
      resolve('promise 상태는 fulfilled!! then으로 연결됩니다. \n 이때의 flag가 true입니다.');
    }else{
      reject('promis 상태는 rejected!! catch로 연결됩니다. \n 이때의 flag는 false입니다.');
    });
  • Promise는 두 가지 콜백함수를 가진다.
    • resolve(value) : 작업이 성공(fulfilled)한 경우, 그 결과를 value와 함께 호출
    • reject(error) : 에러(rejected)발생 시 에러 객체를 나타내는 error와 함께 호출

[콜백함수]를 이용해 동기처리 한 것을 "promise"를 이용해 동기처리 하기

콜백함수

function goMart(){
  console.log('마트에 가서 어떤 음료를 살지 고민한다.')
}
function pickDrink(callback){
  setTimeout(function(){
    console.log('고민 끝!!');
    product = '제로 콜라';
    price = 2000;
    callback(product, price);
  }, 3000);
}

let product;
let price;
goMart();
pickDrink(function(product,price){
  console.log(`상품명: ${product}, 가격 : ${price}`);
});

Promise 사용

function goMart(){
  console.log('마트에 가서 어떤 음료를 살지 고민한다.')
}

function pickDrink(){
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      console.log('고민 끝!!');
      product = '제로 콜라';
      price = 2000;
  	  resolve();
      }, 3000);
   });
 }

function pay(){
  console.log(`상품명 : ${product}, 가격: ${price}`);
}
let product;
let price
goMart();
pickDrink().then(pay);

Promise 체이닝 사용 안한 경우

문제
1. 함수를 이용해 (4+3)*2-1 = 13 연산을 해보자
2. 연산순서 : 덧셈 -> 곱셈 -> 뺄셈

function add(n1, n2, cb){
  setTimeout(function(){
    let result = n1 + n2;
    cb(result);
  }, 1000);
}

function mul(n, cb){
  setTimeout(function(){
    let reulst = n*2;
    cb(result);
  }, 700);
}

function sub(n, cb){
  setTimeout(function(){
    let result = n - 1;
    cb(result);
  }, 500);
  
  add(4,3, function(x){
    console.log('1: ',x);
    mul(x, function(y){
      console.log('2: ',y);
      sub(y, function(z){
        console.log('3: ',z);
      });
    });
  });
  
  실행결과
  1 : 7
  2 : 14
  3 : 13

Promise 체이닝 사용한 경우

  1. add(4,3)이 add함수의 n1,n2에 들어감
  2. let result = n1 + n2 이므로 result = 4+3 = 7
  3. resolve(result) -> then 호출 -> then에 result =7 이됨
  4. 콘솔찍힘 1: 7
  5. mul에 result값 7이 들어감
  6. mul 파라미터 값 n에 7이 들어감
  7. 나머지도 동일하게 연산
결과

체이닝의 장점

  1. then 메서드 연속 사용 -> 순차적인 작업 가능
  2. 콜백지옥에서 탈출
  3. 예외처리 간편
  4. 마지막 catch 구문에서 한번에 에러 처리 가능

async / await

  • 프로미스 기반 코드를 좀 더 쓰기 쉽고 읽기 쉽게 하기 위해 등장, 비동기 처리 패턴 중 가장 최근에 나온 문법
    • async
      • 함수 앞에 붙여 Promise를 반환한다.
      • Promise가 아닌 값을 반환해도 프로미스로 감싸서 반환한다.
    • await
      • '기다리다' 라는 뜻을 가진 영단어
      • Promise 앞에 붙여 Promise가 다 처리될 때까지 기다리는 역할을 하며 결과는 그 후에 반환한다.

실습

Promise로 배경색 변경하기

        setTimeout(function(){
        document.body.style.backgroundColor = 'red';
            setTimeout(function(){
            document.body.style.backgroundColor = 'orange';
                setTimeout(function(){
                document.body.style.backgroundColor = 'yellow';
                    setTimeout(function(){
                    document.body.style.backgroundColor = 'green';
                        setTimeout(function(){
                        document.body.style.backgroundColor = 'blue';
                        }, 1000)
                    },1000)
                }, 1000)
            }, 1000)
        }, 1000)


1. colors배열에 색을 담아준다.
2. async와 for문을 이용해서 출력

Callback -> Promise

  • 콜백함수로 이루어진 코드를 Promise로 변경하기
function call(name, cb){
  setTimeout(function(){
    console.log(name);
    cb(name);
  }, 1000);
}
function back(cb){
  setTimeout(function(){
    console.log('back');
    cb('back');
  }, 1000);
}
function hell(cb){
  setTimeout(function(){
    cb('callback hell');
  }, 1000);
}

call('kim', function(name){
  console.log(name + '반가워');
  back(function(txt){
    console.log(txt + '을 실행했구나');
    hell(function(message){
      console.log('여기는' + message);
    });
  });
});

결과

function call(name){
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      console.log(name);
      resolve(name);
    }, 1000);
  });
}
function back(txt){
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      console.log('back');
      resolve('back');
    }, 1000);
  });
}
function hell(message){
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      // console.log("callback hell");
      resolve("callback hell");
    }, 1000);
  });
}

call('kim')
  .then(function(name){
  console.log(name, "반가워");
  return back();
})
  .then(function(txt){
  console.log(txt+ '을 실행했구나');
  return hell();
})
  .then(function(message){
  console.log("여기는 " + message);
})

promise로 바꾼 코드를 exec 함수를 만들어 실행하게 하기(이때, exec함수는 async 함수이다.)

async function exec(){
  let name = await call('kim');
  console.log(name + '반가워');
  let txt = await back();
  console.log(txt + '을 실행했구나');              
  let message = await hell();
  console.log('여기는' + message);
}
exec();

구조 분해 할당

  • 구조분해 할당(Destructuring assignment)
  • 배열이나 객체의 속성을 해체해 그 값을 개별 변수에 담는 것
  • 배열 구조 분해
  • 객체 구조 분해

배열 구조 분해

const[변수] = 배열;
  • 각 변수에 배열의 인덱스 순으로 값 대응
  • 구조분해 시 변수의 값이 undefined일 때 기본 값 할당가능
  • 구조분해 없이 두 변수의 값 교환도 가능
const lists = ['apple', 'grape'];
//기존 방식
console.log(lists[0], lists[1]);
//[변수] = 배열
[item1, item2, item3 = 'peach'] = lists;
console.log("item1 : ", item1);		// apple
console.log("item2 : ", item2);		// grape
console.log("item3 : ", item3);		// peach

item1 = 'peach';
console.log('item1: ', item1);
console.log(item1);		//item1 : peach

//교환
const x=1, y=3
[x,y] = [y,x];
console.log(x,y);
-> 이건 틀렸음
왜? const는 재선언, 재할당 불가이기 때문에 배열을 통째로 바꾸는건 안됨
1. const 대신에 let 이었으면 변경가능
2. x,y를 통째로 안 바꾸고 하나만 바꿔도 바뀜
const person={
  //key :value
  name : 'gildong',
  age : '22',
  gender : 'M',
  friends ; ['chunhyang', 'chulsu'],
    hello:function(){
      console.log('hello');
    },
      'kdt-9' : 'codingon 9기'
};
//(객체.키)로 키값을 불러올 수 있음
console.log(person.name, person.age);	//gildong, 22
//선언도 가능
person.age = 29;
console.log(person.age);		//29
console.log(person.friends[0]);	//chunhyang
//
console.log(person['name']);	//gildong
console.log(person['kdt-9']);	//codingon 9기
 
객체[] -> 얘는 언제쓰냐?
  키에 특수문자가 들어갈 때 위에 방식처럼 불러와야됨
ex)
person.kdt-9 -> 이거 - 때문에 안됨.
person['kdt-9'] -> 이런식으로 작성해야 정상적으로 불러올 수 있음

// 이런식으로 추가도 가능함
person['city'] = 'Seoul'

person.city = 'Incheon';	//변경도 가능

객체 구조 분해

const{변수} = 객체;
  • 객체 안의 속성을 변수명으로 사용
  • (:)을 이용해 새 변수명을 선언하고, 원래의 값을 새 변수명에 할당할 수 있다.
console.log(name, city, gender); -> 이거 오류남
const{name, city, gender} = person 이렇게 불러와야댐

const{key = 'Hi', age: myAge} = person
-> 변수명 age를 myAge로 바꿔줫음

console.log(person.age);	-> 변수명을 myAge로 바꿔줘서 
age변수는 없어졌기 때문에 이걸로 못불러옴

spread 연산자

const a = [1, 2, 3];
const n = [4, 5];

기존방식(concat)

const concat = a.concat(b);

결과


새로운 방식(spread)

const spread = [...b, ...a];


객체로 spread 연산자 사용 가능

const person={
  name : 'gildong',
  age : 25;
};
console.log({...person});

rest는 파라미터 spread랑 쓰이는 곳이 다르다.

function get(a, ...rest){
  console.log(a, rest)
}
get(10, 20, 30, 40, 50, 60);


spread vs rest

  • spread 파라미터는 호출하는 함수의 파라미터에 사용
  • rest 파라미터는 호출받는 함수의 파라미터에 사용, 호출하는 함수의 파라미터 순서에 맞춰 값 설정 후 남는 파라미터 값을 배열로 설정

클래스

  • 객체를 생성하기 위한 템플릿


객체 : 고양이 그 자체
속성

  • 이름 : 나비
  • 나이 : 1살
    메소드
  • mew() : 울다.
  • eat() : 먹는다.
class Cat{
  constructor(name, age){
    //속성
    this.name = name;
    this.age = age;
  }
  
  //메소드
  mew(){
    console.log("야옹");
  }
  eat(){
    console.log("먹이를 먹습니다.");
  }
}

let cat1 = new Cat('나비', 1);
let cat2 = new Cat('냥이', 2);

cat1.mew();
cat1.eat();
cat2.mew();

결과
- 야옹
- 먹이를 먹습니다.
- 야옹
profile
꾸준히합니다.
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 7월 31일

많은 도움이 되었습니다, 감사합니다.

답글 달기