프로미스 객체
안녕하세요🤗
이번시간에는 비동기 작업을 다룰 때 사용되는 프로미스 객체에 대해 다뤄보도록 하겠습니다.
비동기 처리
저번시간에 배웠던 자바스크립트의 비동기 처리에 대해 다시 한 번 이야기해보겠습니다.
우리는 setTimeout 함수를 이용해 작업을 비동기적으로 처리했었고, setTimeout함수는 작성된 코드와 같이 콜백함수와 ms단위의 지연 시간을 매개변수로 입력받는 함수라고 배웠었습니다.
지난시간 작성했던 이 workA, workB, workC 함수를 비동기 함수로 다시 생성하고, workD는 동기적으로 작성해주겠습니다.
이번에는 이 함수들을 호출할 때, 출력할 단어와, 단어를 출력하는 함수를 인수로 넘겨주도록 하겠습니다.
해당 코드의 실행 결과를 살펴보겠습니다.
먼저 동기 함수 workD가 출력되고, 이후 workB 함수는 "workB" 라는 단어와 console.log로 매개변수로 받은 값을 출력하는 함수를 인수로 전달했습니다.
이 workB 함수에서는 value 값으로 workB 받고, callback 으로는 매개변수로 받은 값을 출력하는 함수를 전달받습니다.
이후 setTimeout의 콜백함수에서 "workB"가 3초 뒤에 출력되고, workC, workA 함수도 동일한 방식으로 실행되어 알맞은 값이 출력됩니다.
여기까지 setTimeout을 사용했을 때 코드의 순서가 어떻게 흘러가는지 이해하셨다면, 자바스크립트의 비동기 처리에 대해 완벽하게 이해하신겁니다.
그렇다면, 이번에는 workA에서 매개변수로 받은 값에 5를 더하고, 그 결괏값을 workB에서 전달받아 다시 3을 빼고, 다시 그 결괏값에 10 더하는 workC 함수로 코드를 변경해보도록하겠습니다.
코드를 실행하면, workD 함수가 동기적으로 처리되어 "workD"가 가장 먼저 출력되고, 이번엔 비동기 함수의 결괏값을 계속해서 전달해야하기 때문에 workA, workB, workC 가 순서대로 실행되어 10에 5를 더한 15, 15에 3을 뺀 12, 12에 10을 더한 22가 출력되는 것을 볼 수 있습니다.
자바스크립트에서 비동기 함수의 결괏값을 또 다른 비동기 함수에서 사용하기 위해, 이렇게 콜백함수 안에 콜백함수를 전달하는 방식으로 전달하게 되면, 함수의 실행 순서를 알기 쉽고, 유연한 프로그래밍을 할 수 있다는 장점이 있지만, 가독성이 매우 좋지 않은 코드가 되어 많은 오류를 발생시킨다는 단점이 있습니다.
우리는 이렇게 > 모양으로 복잡하게 생긴 코드를 콜백 지옥
이라고 부르며, 이러한 콜백 지옥은 프로미스(Promise) 객체
를 이용해 해결할 수 있습니다.
프로미스 객체
프로미스 객체는 비동기 작업을 더 편리하게 처리할 수 있게 도와주는 자바스크립트의 내장 객체입니다.
생성법 부터 알아보겠습니다.
프로미스 객체는 new 키워드와 생성자를 사용해 생성가능합니다.
프로미스 객체를 만들 때에는 인수로 executor 라는 실행함수를 전달합니다.
실행함수란 프로미스 생성자에 반드시 들어가야 하는 함수이며, 작업을 비동기로 처리하는 함수입니다.
3초 후에 실행되는 비동기 함수를 프로미스 객체를 이용해 구현해보겠습니다.
executor 실행함수 안에 setTimeout 함수를 작성해 "3초만 기다리세요" 라는 문장을 출력해보도록하겠습니다.
코드를 실행하면 3초 후에 "3초만 기다리세요" 라는 문장이 출력되는 것을 확인할 수 있습니다.
이렇게 executor 함수는 프로미스 객체를 생성함과 동시에 실행되는 실행함수입니다.
resolve와 reject
여기서 설명 없이 작성만 하고 그냥 넘어간 부분이 있는데요, 바로 executor 함수의 매개변수인 resolve와 reject 콜백함수 입니다.
resolve와 reject은 자바스크립트에서 자체적으로 제공하는 콜백함수으로, executor는 비동기처리가 성공하면 resolve를, 실패한다면 reject를 호출합니다.
비동기 처리 작업은 항상 성공할 수도, 실패할 수도 있기 때문에 이 resolve와 reject 둘 중 하나는 반드시 호출해야합니다.
프로미스 내부 프로퍼티
프로미스는 객체이기 때문에 프로퍼티들을 갖고 있는데요, 더 자세한 설명을 위해 프로미스 객체의 내부 프로퍼티들을 살펴보겠습니다.
프로미스 객체는 state, result 이렇게 두 가지의 내부 프로퍼티들을 갖습니다.
프로미스 객체는 맨 처음 대기(pending) 상태와 undefined의 값을 가지고 있다가, executor 가 호출하는 콜백 함수에 따라 state와 result가 변화됩니다.
그림에서 볼 수 있듯이, executor가 실행되고, 처음엔 대기 상태에 있다가, resolve가 호출 될 경우 프로미스의 state를 fulfilled(성공)로 변경하고, reject가 호출 될 경우 상태를 rejected(실패)로 변경합니다.
result 값도 마찬가지로, 처음엔 undefined의 값을 갖고있다가 resolve가 호출이 되면 value로, reject가 호출이 되면 error 로 변경됩니다.
이렇게 프로미스 객체의 상태는 resolve와 reject를 통해 변하지만, 한 번 변경된 상태는 더 이상 변하지 않기 때문에, 처리가 끝난 프로미스 객체에 resolve 또는 reject를 호출하면, 무시된다는 것을 주의해야합니다.
resolve 와 reject 사용하기
resolve와 reject가 호출 될 때 프로미스의 내부 프로퍼디 값들이 어떻게 변화하는지에 대해 배워보았으니, 이번에는 resolve와 reject의 사용법에 대해 배워보겠습니다.
resolve
3초 후에 "성공" 을 출력하는 비동기 함수를 resolve를 이용해 구현해보겠습니다.
executor 함수에서 비동기 처리된 결과 값을 반환할 때에는, 매개변수로 받은 resolve 콜백함수에 결과값을 전달하면 됩니다.
그리고 이 reslove 콜백함수에 전달된 값은 프로미스 객체의 then 메서드
를 이용해 사용할 수 있고, then 메서드에는 executor 함수에서 전달한 값이 매개변수로 전달됩니다.
그렇기 때문에 이 매개변수를 console.log를 통해 출력까지 해볼 수 있습니다.
작성한 코드를 전체적으로 살펴보도록 하겠습니다.
먼저 프로미스 객체가 생성됨과 동시에 executor 함수가 실행되었고, executor 함수에서는 매개변수로 받은 콜백함수들 중, resolve 함수를 사용해 "성공" 라는 값을 전달했습니다.
이때, 프로미스 객체의 state는 pending 에서 fulfilled 로 변경되고, result는 undefined에서 "성공" 으로 변경됩니다.
그 다음, then 메서드를 통해 프로미스 객체의 result 값을 매개변수로 받아 콘솔에 출력하는 코드입니다.
reject
그럼 번에는 reject를 이용해 비동기 처리가 실패했다고 가정해보고, reject 함수의 사용법을 알아보겠습니다.
executor 함수에서 reject 콜백함수를 사용해 "실패" 라는 값을 전달해보겠습니다.
reject 함수가 실행되었기 때문에, 프로미스 객체의 state는 pending 에서 rejected로, result는 undefined 에서 "실패" 로 변경됩니다.
동일하게 then 메서드를 통해 프로미스 객체의 result 값을 콘솔에 출력해봤지만, 이번엔 아무것도 출력 되지 않는 것을 볼 수 있습니다.
then 메서드는 작업이 성공했을 때 사용되는 메서드이고, 이렇게 reject 함수를 사용해, 작업이 실패했을 때 결괏값을 사용하기 위해서는 catch 메서드를 사용해야 합니다.
이렇게 작업이 실패하게되면, then 메서드는 실행되지 않고, catch 메서드만 실행되어, 콘솔창에 "실패" 라는 값이 전달됩니다.
콜백지옥을 해결하는 Promise 객체
프로미스 객체를 생성하고, executor와 프로미스 객체의 내부 프로퍼티들에 대해 배우면서, 프로미스 객체를 활용해 비동기 작업이 성공했을 때와, 실패했을 때 처리하는 방법까지 알아보았습니다.
마지막으로는 우리가 프로미스 객체를 배우기 전에 겪었던 콜백지옥
함수를 지금까지 배운 프로미스 객체를 사용해 작성해보겠습니다.
콜백지옥을 설명했던 예시 그대로, workA, workB, workC 함수를 프로미스 객체를 사용해 비동기 함수로 작성해보도록하겠습니다.
동일하게 이 세 가지 함수를 생성하고, 이번에는 콜백함수를 사용한 비동기 처리가 아닌, 프로미스 객체를 사용하기 때문에, 콜백함수가 필요 없어져 매개변수로는 value 라는 숫자만 받아줍니다.
함수의 내부에 프로미스 객체를 생성해주겠습니다.
이번에는 executor 함수를 별도로 작성하지 않고, 바로 콜백함수로 넣어주도록 하겠습니다.
executor 함수는 resolve와 reject 두 가지 콜백 함수를 필요로 하기 때문에 매개변수로 전달해주고, setTimeout을 사용해 비동기 처리를 해주겠습니다.
그 다음, value 라는 매개변수를 받아 value 값에 5를 더한다음, 이 결괏값을 resolve 를 통해 전달하도록 하겠습니다.
workA와 마찬가지로 workB, workC 함수도 동일하게 작성해주도록하겠습니다.
이번엔 workA함수를 호출하고, then 메서드를 사용해 결괏값을 반환 받고, 전달 받은 결괏값을 다시 workB 함수에 전달해주도록하겠습니다.
이렇게 작성해본 결과, 코드가 많이 깔끔해지긴 했지만, 여전히 콜백지옥 코드의 모양과 비슷하기 때문에 많은 차이가 있지는 않다고 느끼실 겁니다.
그럼 이 then 메서드를 한 번 다른 방식으로 사용해보겠습니다.
프로미스 체이닝
이번에는 then 메서드의 콜백함수 안에서, workB함수를 리턴해주도록하겠습니다.
이렇게 workB 함수가 반환되게 되면, workB 함수의 반환값인 프로미스 객체가 반환되는 것이기 때문에, 다시 한번 then을 사용할 수 있게 됩니다.
이렇게 계속해서 프로미스 객체를 반환하며, then 메서드를 연속으로 사용하는 것을 "프로미스 체이닝" 이라고 부릅니다.
프로미스 체이닝을 사용해 코드를 작성하면, 코드를 아래쪽으로 계속 작성할 수 있기 때문에 훨씬 직관적으로 코드를 해석할 수 있고 코드가 깔끔해지는 것을 볼 수 있습니다.
이번시간에는 이렇게 프로미스 객체에 대해 배우고, 콜백지옥을 해결하는 방법까지 알아보았습니다.
자바스크립트 응용하기 챕터의 내용으로, 살짝 어려울 수 있는 개념인 만큼, 강의 자료와 함께 강의를 두 번 이상 학습 하시는 것을 추천드립니다.
다음시간에는 이 프로미스 객체를 더 쉽게 사용할 수 있는 async/awiat에 대해 배워보도록 하겠습니다.
감사합니다.
Last updated