본문 바로가기

Front-End

Delaying of Function

728x90

INDEX

    Stack

    #VanillaJS

     

    Preview

    JS로 개발하다 보면 비동기 처리에 항상 신경을 쓸 수밖에 없습니다.

     

    *https://sieon-dev.tistory.com/56

    이전 포스팅에서 한 번 다뤘었는데 좀 부족한 듯해 추가로 다뤄보려 합니다.
    (나중에 보면 이 글도 많이 부족해보이겠죠..ㅎ)

     

     

    Methodology

    만약 얼마나 걸릴지 알수없는 함수 longTimeFunc(Function) 가 있고 그 함수를 호출해야 하는 함수는 오래 걸리는 메서드의 프로세스가 끝난 뒤에 결과 값을 출력해야 하는 경우라면 어떻게 해야 할까요?

    const RandomTimeSec = parseInt(Math.random() * 10);
    
    const longTimeFunc = () => {
      setTimeout(() => {
        console.log(RandomTimeSec + "초만큼 걸렸네요");
      }, RandomTimeSec * 1000);
    };
    
    const originalFunc = () => {
      longTimeFunc();
      console.log("originalFunc 끝났습니다.");
    };
    
    originalFunc();
    //result
    originalFunc 끝났습니다.
    6초만큼 걸렸네요

    originalFunc 끝났습니다가 나중에 찍혀야 한다면..

     

    Callback

     

    const RandomTimeSec = parseInt(Math.random() * 10);
    
    const longTimeFunc = (callback) => {
      setTimeout(() => {
        console.log(RandomTimeSec + "초만큼 걸렸네요");
        callback();
      }, RandomTimeSec * 1000);
    };
    
    const originalFunc = () => {
      const printResult = () => {
        console.log("originalFunc 끝났습니다.");
      };
      longTimeFunc(printResult);
    };
    
    originalFunc();
    6초만큼 걸렸네요
    originalFunc 끝났습니다.

     

    가장 Basic 한 방법입니다. 

    나중에 실행해야 하는 로직을 callback 함수에 담아 보내고 longTimeFunc이 다 끝나면 해당 함수를 실행시킵니다.

    다만, callback함수를 쓰는 것은 실행해야 할 함수가 많아지면 어떤 게 어떤 함수의 callback 인지 헷갈리는 경우가 있기 때문에 가독성이 떨어집니다.

     

    Callback을 사용하는 방법도 다양합니다. new Promise, async await를 사용할 수도 있습니다.

    /*new Promise 사용하기*/
    const RandomTimeSec = parseInt(Math.random() * 10);
    
    const longTimeFunc = (callback) => {
      setTimeout(() => {
        console.log(RandomTimeSec + "초만큼 걸렸네요");
        callback();
      }, RandomTimeSec * 1000);
    };
    
    const originalFunc = () => {
      console.log("originalFunc 끝났습니다.");
    };
    
    new Promise((resolve) => {
      longTimeFunc(resolve);
    }).then(() => {
      originalFunc();
    });
    3초만큼 걸렸네요
    originalFunc 끝났습니다.

    new Promise then을 사용하면 로직자체가 한눈에 들어옵니다. 하지만 더 한눈에 들어오게 하는 방법이 있습니다.

    /*async await 사용하기 */
    const RandomTimeSec = parseInt(Math.random() * 10);
    
    const longTimeFunc = () => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log(RandomTimeSec + "초만큼 걸렸네요");
          resolve();
        }, RandomTimeSec * 1000);
      });
    };
    const originalFunc = async () => {
      await longTimeFunc();
      console.log("originalFunc 끝났습니다.");
    };
    
    originalFunc();

    async await를 쓰면 await이라는 단어 때문인지 어떤 함수를 기다리고 어떤 절차로 진행되는지 파악하기가 더 쉬워집니다.

     

    new Promise 안에 resolve는 한 가지 비밀이 있는데 다음 실행해야 할 함수에 첫 번째 파라미터만 전달할 수 있습니다.

    const RandomTimeSec = parseInt(Math.random() * 10);
    
    const longTimeFunc = () => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log(RandomTimeSec + "초만큼 걸렸네요");
          resolve(1, 2);
        }, RandomTimeSec * 1000);
      });
    };
    const originalFunc = async () => {
      let result = await longTimeFunc();
      console.log(result);
    };
    
    originalFunc();
    8초만큼 걸렸네요
    1

    *만약 longTimeFunc에서 여러 개의 값을 return 해야 하는 상황이 온다면 배열에 담거나 object에 담아 resolve로 보내야 합니다.

    /*async await 사용하기 */
    const RandomTimeSec = parseInt(Math.random() * 10);
    
    const longTimeFunc = () => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log(RandomTimeSec + "초만큼 걸렸네요");
          resolve({ first: 1, second: 2 });
        }, RandomTimeSec * 1000);
      });
    };
    const originalFunc = async () => {
      let result = await longTimeFunc();
      console.log(result);
    };
    
    originalFunc();
    2초만큼 걸렸네요
    { first: 1, second: 2 }

    여러 가지 방법이 있지만 혼자만 개발하는 것이 아니니 최대한 다른 사람이 보기에도 한 눈에 읽히는 코드를 짜야하는걸 매번 느낍니다. 더 Clean한 코드를 짜는 날까지!