[Node.js] 여러 개의 계산 중, 내가 원하는 조건이 되었을 때 함수를 불러와서 호출 스택의 가장 위에 놓는 방법.

조회수 626회

안녕하세요.

궁금한 점이 있어 이렇게 질문을 올립니다.

먼저 코드로 설명을 해보겠습니다.

function a(){ // 한 번 도는데 100~150 ms 걸리는 함수. for에서 시간이 많이 걸림.
    for(){
        // 계산, 계산, 계산........
        if( 계산 도중 조건을 만족 ){
            b(); // func b()를 호출
        };
    };
};

function b(){
    c(()=>{
        d(()=>{
            console.log('도착!');
        });
    };
};

function c(callback){
    callback(null);
};

function d(callback){
    callback(null);
};

// Run
setInterval(()=>{
    a(); // func a()를 호출하여 시작
}, 200);

위와 같은 형태의 프로그램을 만들었는데 몇가지 궁금증이 생겨서 질문을 올립니다.

Q.질문

  1. 위의 프로그램에서 a()에서 조건 만족시 b()를 호출했을 때 b(),c(),d()가 각각 호출 스택(call stack)의 제일 위에 쌓이게 되는 건가요?
  2. 혹시 제일 위에 쌓이지 않는다면 d()가 테스크 큐(task queue)에 쌓여 느려질 것이라 생각되는데 맞나요?

만약 위의 두 개 다 틀렸다면 b(),c(),d()를 호출 스택(call stack)의 가장 위에 쌓는 방법을 알고 싶습니다.

현재 제가 가진 문제는 b()를 개별적으로 호출 했을 때와 위처럼 a() 실행 안에서 실행했을 때 호출되는 속도가 차이가 나는 게 문제입니다.

p.s. 코드를 위와 같이 작성한 이유는 callback에서 response를 받아서 처리해야 하는 부분이 있기 때문입니다.

  • a() 함수 내부의 반복문을 탈출하는 로직이 있나요? 그리고 속도 차이는 어떻게 확인하셨나요? doodoji 2018.10.16 13:47
  • 일단 setInterval로 등록한 함수가 event(task) queue에 쌓입니다. 이건 자명한 사실인데 a()함수는 200ms 이후에 실행되고 a()에 선언된 for문도 돌아야 되므로 첫번째 b()가 호출되는 시기는 대략 200 + (100~150) = 300~350ms 정도 이후가 되겠네요. 만약 a()내부 for문의 프로세싱이 계속해서 200ms를 넘어가는 상황이 되면 그때부터 b()의 호출 주기 또한 200ms를 넘기게 됩니다. doodoji 2018.10.16 13:58
  • @digda 제가 이해가 안 되서 그러는데 정리를 해보겠습니다. a()함수가 전체 도는 데 200ms가 걸리는 상황인데 첫번째 b()가 호출되는 게 조건이 맞아서 호출되는 것이 아니라 a()함수가 다 끝나고 그다음에 b()가 호출된다는 말씀이신가요? 그리고 속도 차이는 b()에 들어가서 시작 할 때 Date.now()를 설정하고 d()의 콜백 안에서 Date.now() 변수를 만든 다음에 둘의 차이로 비교했습니다. 반복문을 탈출하는 로직은 for( ; && boolean ; ) 이런 형식으로 조건문이 돌다가 boolean이 false로 바뀌게 되어 반복문을 탈출하도록 만들었습니다. TaeSun Yoo 2018.10.21 22:07

1 답변

  • 좋아요

    1

    싫어요
    채택 취소하기

    1.

    200ms 이후에 a가 실행되며 a가 콜스택에 쌓입니다. 조건을 만족하면 (익명함수 제외) b,c,d가 추가적으로 콜스택에 쌓이는게 맞습니다.

    그런데 a라는 함수의 실행시간이 interval로 지정한 200ms보다 크게 되면 콜스택이 비는 가장 빠른 타이밍(이 전 b,c,d가 모두 끝난, a함수 종료 시점)에 실행을 할 뿐, 다음 a함수 콜을 200ms 에 딱 맞추어 overlap 하여 실행하지 않습니다. 이는 메인 코드를 실행하는 쓰레드는 하나라는 특성에 기인합니다.

    위에 제가 단 댓글에도 언급해 드렸듯, a라는 함수의 수행시간이 200ms가 넘어가게 되면 그 시점에는 주기가 200ms가 아닐 수 있다는 말입니다.

    2.

    setInterval은 함수 구현 특성상 한 번에 하나의 함수만을 실행하게 됩니다. 즉, 이 전의 호출이 끝나기 전까지 시간이 만료되었다 하더라도 다음 호출은 발생하지 않아요. 때문에 위 로직에서는 어딘가에 함수 콜이 쌓여 느려질 것을 염려하실 필요는 없습니다. 만약 애초에 그렇게 쌓일 상황이었다면 call stack이 넘쳤다는 에러(maximum call stack size exceeded)를 먼저 보셨을 겁니다.


    아무튼, 코드는 절대 병렬 실행되지 않습니다. a함수는 콜스택에 쌓이고 내부에서 호출하는 함수들도 순차적으로 쌓입니다. 그리고 역순으로 비워집니다. 모두 비워지고 나서야 다음 a함수 콜이 콜스택에 쌓이게 됩니다. 이 일련의 함수 호출이 하나의 묶음으로 동작하기 때문에 다음 차례의 b,c,d가 이전 a함수 실행 도중에 끼어들어 먼저 실행될 수 없습니다.

    만약 b,c,d 함수중 하나라도 async 함수가 있다면 얘기는 좀 달라질 수 있겠네요. 200ms가 넘어가는 주기가 계속되거나 비동기 콜백이 늦게 호출되는 상황이면 특정 시점에 호출이 몰린다거나 호출 순서와 상관없이 콜백이 실행되는 상황... 이래저래 더 복잡해지겠죠. (이건 생각하기도 싫네요. ㅎ)

    • 이제야 좀 알 것 같습니다! 감사합니다! TaeSun Yoo 2018.10.22 18:49

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)