ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • NodeJS - Promise, async/await
    개발언어/Node.js 2023. 3. 27. 15:51

    Promise

    function findAndSaveUser(Users) {
      Users.findOne({})
        .then((user) => {
          user.name = "surge100";
          return user.save();
        })
        .then((user) => {
          return Users.findOne({ gender: "m" });
        })
        .then((user) => {
          //생략
        })
        .catch((err) => {
          console.error(err);
        });
    }

    Promise.all(배열): 여러 개 의 프로미스를 동시에 실행

    • 하나라도 실패하면 catch로 간다.
    • allSettled로 실패한 것만 추려낼 수 있다.

    콜백 헬이라고 불리는 지저분한 자바스크림트 코드의 해결책

    • 프로미스 : 내용이 실행은 되었지만 결과를 아지 반환하지 않은 객체
    • then을 붙이면 결과를 반환한다.
    • 실행이 완료되지 않았으면 완료된 후에 then 내부 함수가 실행된다.

     

    • resolve(성공리턴값) -> then으로 연결
    • reject(실패리턴값) -> catch로 연결
    • finally 부분은 무조건 실행된다.

    프로미스객체를 활용해서 보낸 요청이 항상 성공하는 것은 아니다. 비동기로 실행하는 코드는 항상 실패할 수도 있는다는 가능성을 열어 두어야한다.

     

    만약에 실패를 했는데 resolve를 부른 경우 해당 실패결과가 then으로 간다. 코드의 성공과 실패여부를 잘 판가름해서 resolve/reject를 사용해야한다.


    async/await

    • 이전 챕터의 프로미스 패턴 코드를 한번더 축약가능하다.

    async function의 도입

    • 변수 = await 프로미스; 인 경우 프로미스가 resolve된 값이 변수에 저장
    • 변수 await 값; 인 경우 그 값이 변수에 저장
    async function findAndSaveUser(Users) {
      let user = await Users.findOne({});
      user.name = "zero";
      user = await user.save();
      user = await Users.findOne({ gender: "m" });
    }

    실행 코드 앞에 await을 붙여서 await가 then 역할을 한다고 생각하면 된다. 즉 .then()을 한 뒤에 결과 값을 return하는 것이 아니라 바로 성공결과 값을 받는 것이다.

     

    그래서 await의 실행순서를  await 기준으로 오른쪽에서 왼쪽으로 생각하면된다.

    프로미스 체인은 위에서 아래로 await 함수 실행은 오른쪽에서 왼쪽으로 실행된다. await으로 함수를 실행하려면 함수 정의시 앞에 async 예약어를 붙여야 한다.

     

    과거의  then을 사용한 코드

    const promise = new Promies(...)
    
    promise.then((result) => ...)

     

    await을 활용한 코드로 변경

     

    case1

    const result = await promise; // 작동(❌)

     

    case1이 작동하지 않는이유는 await을 사용하기 위해선 작동할 함수도 async 함수로 정의가 되어 있어야 하고, await사용하는 코드 자체도 async함수 블록 안에 감싸있어져 있어야 하기 때문이다.

     

    case2

    async function main(){
      const result = await promise;
    }
    
    main();

    case2처럼 async함수 정의을 할때 안에서 await을 사용한뒤 해당 함수를 따로 실행해야 했다. await은 항상 async function안에서만 실행되어야 하기때문이었다.

     

    Top level await 

    top level await이라는 개념이 등장해서 요즘에 case1과 같이 적힌 코드도 동작이 가능하다.

     

    then 사용 혹은 await 사용

    async function main(){
      const result = await promise;
      return 'surge100'; 
    }
    
    main().then((name) => ...)

    async함수에서 return 값은 위 코드와 같이 해당 함수를 실행한 다음에 함수 chain을 사용해서  .then으로 받아야한다.

     

    async function main(){
      const result = await promise;
      return result; 
    }
    
    main().then((name) => ...)
    
    const name = await main();

    하지만 async도 promise이기 때문에 then을 않고 위 코드와 같이 await을 활용하여 함수를 실행한 뒤에 반환 값은  name변수에 넣어 줘도 된다.

     

    async의 결론은 Promise이다. Promise의 문법을 간단한게 만든 것이기 때문에 async도 결국 Promise이기 때문에 Promise의 성질을 그대로 가진다.

     

    try ~ catch문 사용

    async function main(){
    
    try{
      const result = await promise;
      return result; 
     }catch(error){
      console.log(error);
     }
    }

    문법은 then을 사용하거나 await을 사용하거나 하나를 선택하면 된다. 하지만 async/ await을 사용할 때는 .catch()함수를 붙일 수 없다. 그럴 때는 try ~catch문을 사용해서 감싸주면 된다.

     

    async/await이 Promise와 똑같은데, resolve만 있고 reject를 처리할 수 있는 부분이 없어서, try ~ catch문의 catch 블록안에서 처리해주어야 한다.

     

    Async 함수는 항상 promise를 반환(return)

    • Then이나 await을 붙일 수 있다.
    async function findAndSaveUser(User){
      //생략
    }
    
    findAndSaveuser().then(() => {/* 생략 */});
    //또는
    
    async function other(){
      const result = await findAndSaveUser();
    }

    for await of

    for await (변수 of 프로미스 배열)

    • 노드 10부터 지원
    • resolve된 프로미스 변수에 담겨 나온다.
    • 결국 await이기 때문에 async 함수 안에서 사용 해야한다.
    const promise1 = Promise.resolve('성공1');
    const promise2 = Promise.resolve('성공2');
    (async () => {
     for await (promise of [promise1, promise2]){
       console.log(promise);
     }
    })

    await은 즉 then()메서드와 같다고 생각해도 무방하다. then 이라는 것을 활용해서 Promise 타입을 item으로 갖는 배열에 반복문을 돌릴 수 있다.

     

    💡프로토타입(prototype)을 알아야 하는 이유

    라이브러리를 사용할 때 즉 다른 사람이 적은 코드를 사용하거나 분석해야 하는 일이 생길 때, 해당 코드가 객체지향적으로 쓰였는지 함수프로그램으로 쓰였는지 알 수 없다.

    객체 지향적 프로그램으로 쓰인 코드는 프로토타입을 자주 사용한다. 스스로 따라서 스스로 객체지향 프로그래밍 방식을 사용하지 않더라고 프로토타입에 대해 알아 두어야 타인의 코드를 사용하고 해석할때 불편함을 겪지 않을 수 있다.

     

    출처 - https://www.inflearn.com/course/%EB%85%B8%EB%93%9C-js-%EA%B5%90%EA%B3%BC%EC%84%9C/dashboard

    댓글

Designed by Tistory.