[생활코딩] JavaScript-Promise (callback & async)

Jang·2022년 9월 6일

생활코딩

목록 보기
7/7
post-thumbnail

출처 : https://www.youtube.com/playlist?list=PLuHgQVnccGMBVQ4ZcIRmcOeu8uktUAbxI

callback (콜백함수)

  • first class citizen (일급시민, 일급객체)
    • val = 1
      • 1은 변수가 될 수 있다 -> 숫자는 일급시민
    • val = if() {}
      • 조건문은 변수가 될 수 없다. -> 일급시민X, 2급시민O
    • val = function() {return}
      • 함수는 변수가 될 수 있다. -> 함수는 일급시민


val은 fn이라는 함수 안에서 호출되는 함수.
val은 지금 바로 실행되진 않지만 다른 함수의 입력값으로 전달되어서
다른 함수에 의해서 나중에 호출된다.
val은 이 맥락에서 CALLBACK FUNCTION이 된다.



예시 Array.prototype.filter()

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);  // words.filter(callback()); 
	                                                   // callback에서 true를 리턴하는 값을 result에 저장
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]

구문

arr.filter(callback(element[, index[, array]])[, thisArg])

매개변수

  • callback
    각 요소를 시험할 함수. true를 반환하면 요소를 유지하고, false를 반환하면 버립니다.
    다음 세 가지 매개변수를 받습니다.

    • element
      처리할 현재 요소.

    • index Optional
      처리할 현재 요소의 인덱스.

    • array Optional
      filter를 호출한 배열.

    • thisArg Optional
      callback을 실행할 때 this로 사용하는 값.

const words = ["spray", "limit", "elite", "exuberant", "destruction", "present"];

function myfilter(origin, callback) {
  var result = [];
  for (var i = 0; i < origin.length; i++) {
    var current = origin[i];
    if (callback(current)) {
      result.push(current);
    }
  }
  return result;
}

const newWords = myfilter(words, (wr) => wr.length > 6);
console.log(newWords);
// 위 filter 코드와 동일하게 작동한다.




Promise (then, catch)

동기 (Synchronous)비동기 (Asynchronous)
순차적으로 실행됨 -> 어떻게 실행될 것인지 파악하기 쉬움동시에 여러가지 일을 함 -> 혼란스럽지만 빠른 속도로 실행됨
각자가 자신의 시간표에 따라 동작
어떤 명령을 실행할 때 그 명령이 언제 끝나는지 예측하기 어렵거나 ex)네트워크
또는 주가 되는 작업이 아닐 때 주로 씀
  • 동기 (Synchronous)
    • 순차적으로 실행됨 -> 어떻게 실행될 것인지 파악하기 쉬움
  • 비동기 (Asynchronous)
    • 각자가 자신의 시간표에 따라 동작
    • 동시에 여러가지 일을 함 -> 혼란스럽지만 빠른 속도로 실행됨

Promise는 콜백함수가 필요함





async & await

  • callback hell
timer(1000,function(){
  console.log('작업');
  timer(1000,function(){
    console.log('작업');
    timer(1000,function(){
      console.log('작업');
    });
  });
});
// 함수안에 함수가 계속 들어감
  • promise
timer(1000)
  .then(function () {
    console.log("작업");
    return timer(1000);
  })
  .then(function () {
    consol.log("작업");
    return timer(1000);
  })
  .then(function () {
    console.log("작업");
  });
// Promise를 이용하면 함수안에 넣을 필요 없이 체이닝됨
  • 위의 코드가 너무 복잡함
  • 비동기적인 코드를 아래처럼 동기적인 코드같이 작성하고 싶음
  • async , await를 이용하면 됨

// Promise
function timer(time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(time);
    }, time);
  });
}
  • then 이용할 때

    console.log("start");
    timer(1000)              // timer() 함수는 Promise를 리턴
      .then(function (time) {  // 따라서 그 promise를 의미하는 .then과 그 안에 콜백함수
        console.log("time:" + time);
        return timer(time + 1000);
      })
      .then(function (time) {
        console.log("time:" + time);
        return timer(time + 1000);
      })
      .then(function (time) {
        console.log("time:" + time);
        console.log("end");
      });
  • async & await 를 이용하면

    async function run() {         // await를 사용하려면 async 함수가 필요한데 그냥 function앞에 async를 붙여주면 됨
      console.log("start");
      var time = await timer(1000);
      console.log("time:" + time);
      time = await timer(time + 1000);
      console.log("time:" + time);
      time = await timer(time + 1000);
      console.log("time:" + time);
      console.log("end");
    }
    run();  // async 함수인 run은 promise를 리턴함

    => 코드가 훨씬 간단해짐

    • async 함수인 run은 promise를 리턴함
      // 위 코드에 이어서 작성
      async function run2() {
        console.log("parent start");
        await run();                 // run()은 promise를 리턴하므로 await를 붙일수 있음
        console.log("parent end");
      }
      run2(); // run2()또한 promise를 리턴

async function run() {
  console.log("start");
  var time = await timer(1000);
  console.log("time:" + time);
  time = await timer(time + 1000);
  console.log("time:" + time);
  time = await timer(time + 1000);
  console.log("time:" + time);
  console.log("end");
}

async function run2() {
  console.log("parent start");
  await run();
  console.log("parent end");
}

console.log("p p start");
run2().then(function () {
  console.log("p p end");
});

async function run() {
  console.log("start");
  var time = await timer(1000);
  console.log("time:" + time);
  time = await timer(time + 1000);
  console.log("time:" + time);
  time = await timer(time + 1000);
  console.log("time:" + time);
  console.log("end");
  return time;					// async가 time을 리턴하면
}

async function run2() {
  console.log("parent start");
  var time = await run();		// time값을 받아서 쓸수 있음 
  console.log("time:" + time);
  console.log("parent end");
}

console.log("p p start");
run2().then(function () {
  console.log("p p end");
});




Promise 2 - new Promise

function job1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("resolved OK");
    }, 2000);
  });
}

// resolve() 안의 값이 data에 들어감
job1().then(function (data) {
  console.log("data:", data);
});

function job1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("resolved OK");
    }, 2000);
  });
}
function job2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("resolved OK");
    }, 2000);
  });
}

// resolve() 안의 값이 data에 들어감
job1().then(function (data) {
  console.log("data1:", data);
  job2().then(function (data) {
    console.log("data2:", data);
  });
});
// then을 안에 넣는게 아니라 체이닝 할수 있음
job1()
  .then(function (data) {
    console.log("data1", data);
    return job2();
  })
  .then(function (data) {
    console.log("data2", data);
  });

  • resolve 를 reject로 바꾸면
    function job1() {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          reject("rejected FAIL");   // resolve 를 reject로 바꾸면
        }, 2000);
      });
    }

에러가 난다.
이 에러를 잡고 싶다면

  • catch를 사용

    job1()
      .then(function (data) {
        console.log("data1", data);
        return job2();
      })
      .catch(function (reason) {   // 파라미터로 에러난 이유를 받는 콜백함수
        console.log("reason: ", reason);
      })
      .then(function (data) {
        console.log("data2", data);
      });


    data2까지 출력이 됨

  • data2를 받기 싫다면 (에러 이후에 내용을 받지 않으려면) return Promise.reject();를 넣어주면 됨

    job1()
      .then(function (data) {
        console.log("data1", data);
        return job2();
      })
      .catch(function (reason) {
        console.log("reason: ", reason);
        return Promise.reject();          // 이 내용 추가
      })
      .then(function (data) {
        console.log("data2", data);
      });
    

  • catch까지만 실행되고 그 이후는 에러 처리가 됨

    에러 내용중 reason "undefined" 라는 내용을 볼 수 있는데
    return Promise.reject() 괄호가 비어있기 때문


  • return Promise.reject(reason) 이렇게 reason을 넣어주면

Promise에서 입력했던
reject("rejected FAIL");
이 내용이 나오게 됨


  • 전체 코드
function job1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject("rejected FAIL");
    }, 2000);
  });
}
function job2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("resolved OK");
    }, 2000);
  });
}

// // resolve() 안의 값이 data에 들어감
// job1().then(function (data) {
//   console.log("data1:", data);
//   job2().then(function (data) {
//     console.log("data2:", data);
//   });
// });

job1()
  .then(function (data) {
    console.log("data1", data);
    return job2();
  })
  // 파라미터로 에러난 이유를 받는 콜백함수
  .catch(function (reason) {
    console.log("reason: ", reason);
    return Promise.reject(reason);
  })
  .then(function (data) {
    console.log("data2", data);
  });




Promise All | Race - 동시작업을 단순하게!

  • 우리가 관심있는 것은 동시에 실행되는 작업 (asynchronous 비동기)

  • Promise.all

    function timer(time) {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve(time);
        }, time);
      });
    }
    console.time("Promise.all");
    Promise.all([timer(1000), timer(2000), timer(3000)]).then(function (result) {
      console.log("result: ", result);
      console.timeEnd("Promise.all");
    });

  • Promise.race

    function timer(time) {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve(time);
        }, time);
      });
    }
    
    console.time("Promise.race");
    Promise.race([timer(1000), timer(2000), timer(3000)]).then(function (result) {
      console.log("result: ", result);
      console.timeEnd("Promise.race");
    });
    



(2022-09-07) 아직 Promise란 개념이 생소해서 여러번 들여다 봐야 할 것 같다.

그리고 지금 알았는데 velog에서 #을 이용해 제목태그를 작성하면 글을 읽을때 옆에 목차가 생기는데
지금까지

제목

이런 식으로 작성해서 목차가 안생겼다.

0개의 댓글