TIL 11일차 ( callback promise async )

KHW·2021년 8월 19일
0

TIL

목록 보기
10/39

1. import export 모듈을 사용하는 이유

  1. 사용되거나 사용하지 않는 스크립트 추적 가능
  2. script로 여러개를 불러오는 것은 순서가 중요하지만
    import로 불러오는 경우 순서는 무관
  3. script src와 다르게 전역오염이 일어나지 않는다.

2. 비동기

비동기종류

  1. 이벤트 리스너 : 두번째인자가 바로 실행되지 않고 이벤트가 발생할 때 실행
  2. setTimeout
  3. setInterval
  4. XMLHttpRequest

async 방식 / sync 방식

sync 방식은 콜백지옥이 나는 async에 비해 가독성이 좋지만 응답이 오기전까지 브라우저가 굳는 안좋은 결과가 발생하기 때문에 사용을 지양한다.

ex) Api 조회 한다고 10초 걸리는데 이 10초간 브라우저가 먹통 상태


3. Promise / Callback / Async

Promise란?

콜백지옥을 벗어나기 위한 비동기 작업 제어를 위해 사용

resolve 또는 reject를 반환하고 이를 처리하기 위해 .then / .catch / .finally 3가지의 메소드가 존재한다.


Async await

여전히 Promise에서 쓰이는 불편한 부분을 코드 실행을 순차적으로 실행하게 만드는 역할을 해준다.


Callback 예시

function firstCallback(){
  const first = 'first'
  setTimeout(()=>{secondCallback(first)},1000)
}

function secondCallback(data){
  const second = 'second'
  setTimeout(()=>{thirdCallback(data + ' ' + second)},1000)
}

function thirdCallback(data){
  const third = 'third'
  setTimeout(()=>{console.log(data + ' ' + third)},1000)
}

firstCallback();

Promise 예시


function first(){
  const first = 'first'
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(first)
    },1000)
  })
}

function second(data){
  const second = 'second';
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(data + ' ' + second)
    },1000)
  })
}

function third(data){
  const third = 'third';
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(data + ' ' + third)
    },1000)
  })
}

first().then((data)=>second(data)).then((data)=>third(data)).then(result=>console.log(result))

Async await 예시

function asyncFirst(){
  const first = 'first';
  return new Promise((resolve)=>setTimeout(()=>resolve(first),1000))
}

function asyncSecond(val){
  const second = 'second';
  return new Promise((resolve)=>setTimeout(()=>resolve(val + ' ' + second),1000))
}

function asyncThird(val){
  const third = 'third';
  return new Promise((resolve)=>setTimeout(()=>resolve(val + ' ' +third),1000))
}

async function asyncAll(){
  const firstVal = await asyncFirst();
  const secondVal = await asyncSecond(firstVal);
  const thirdVal = await asyncThird(secondVal);
  console.log(thirdVal);
}

asyncAll();

결과

위의 3가지 경우 모두 같은 결과이다.
이를 Callback으로 하면 콜백지옥에 빠지고
Promise를 하면 순차적이긴 하지만 좀 더 직관적인 순차가 부족하고
이를 보완해주는 것이 async await이다.


비동기 에러 핸들러

Promise의 경우 .catch를 사용하고
async await은 해당 await 부분을 try { }로 묶고 그아래 catch()를 처리한다.


4. 의존성 없는 각각의 API를 처리하는 Promise 메소드

1) Promise.all

각각의 API를 처리하고 전부 끝나면 을 반환한다.

  • 주의 : 하나라도 reject가 나면 정상 결과가 나타나지않는다.

예시

const promise1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 3000);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(2);
  }, 2000);
});

const promise3 = Promise.reject(3);

Promise.all([promise1, promise2, promise3])
  .then((result) => console.log(result))
  .catch((e) => console.error(e));
  • 결과 : 에러처리되고 종료

AJAX 예시

return Promise.all([
        Promise.resolve(productOptions),
        Promise.all(
        productOptions.map(productOption => request(`/product-option-stocks?productOption.id=${productOption.id}`))
      )])
  1. 안쪽 Promise.all에서 여러 url에 대해 request를 진행하였고
  2. Promise.resolve(productOptions)부분도 함께 리턴하기 위해 Promise.all을 사용했다.

2) Promise.allSettled

각각의 API를 처리하고 배열형태로 각각의 처리값을 합쳐 반환한다.

예시

const promise1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 3000);
});

const promise2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(2);
  }, 2000);
});

const promise3 = Promise.reject(3);

Promise.allSettled([promise1, promise2, promise3])
  .then((result) => console.log(result))
  .catch((e) => console.error(e));
  • 결과 : 에러가 나지않고 배열 형태로 전부 반환
[
  { status: 'fulfilled', value: 1 },
  { status: 'fulfilled', value: 2 },
  { status: 'rejected', reason: 3 }
]

3) Promise.race

resolve든 reject든 가장 빠른 API 동작 하는 것이 끝나면 바로 끝낸다.

예시

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
});
  • 결과 : 가장 빠른 것이 reject이므로 결과가 나타나지않고 실행종료

4) Promise.any

resolve대상으로 가장 빠른 API 동작 하는 것이 끝나면 바로 끝낸다.

예시

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, 'two');
});

Promise.any([promise1, promise2]).then((value) => {
  console.log(value);
});
  • 결과 : 가장 빠른 reject된 two는 무시하고 그다음 resolve인 one 출력

코드 피드백

1. 직접 외부변수까지 변화시키지 않기

let a = [1,3,5,4,2]
function x(arr){
  arr.sort();
}
x(a);
console.log(a);

의도하지않은 외부 함수인 a에까지 영향을 주는 해당 코드는 지양하고

function x(arr){
  arr = Array.from(arr).sort();
}

이렇게 수정할 경우 참조한 매개변수인 외부변수는 값이 변하지 않는다.


느낀점

Promise의 all메소드 말고 race, any allSettled이라는 것을 새롭게 알 수 있었고 전반적인 비동기를 복습할 수 있었다.

profile
나의 하루를 가능한 기억하고 즐기고 후회하지말자

0개의 댓글