[ES6] Promise함수(1)

권준혁·2020년 11월 1일
0

javascript

목록 보기
15/19
post-thumbnail
post-custom-banner

안녕하세요!

이번포스팅에서는 자바스크립트 빌트인 객체 Promise에대해 알아보겠습니다.

  • Promise
  • Asynchronous

  • constructor

  • State

  • Promise Chaining

  • JS에서의 작동원리


1. Promise

1-1. 비동기

Asynchronous(비동기) <=> Synchronous(동기)

동기식은 순서가 정해져있고 하나가 완료되면 다음순서가 진행되는 식입니다
비동기는 준비가 완료되는 것 부터 실행하기때문에 동시에 실행될 수 있습니다.
비동기의 가치는 처리중인 지연된 정보를 기다리는동안 다른 코드를 또 실행할 수 있다는 점입니다. API응답을 기다리는동안 사용자는 다른 요청을 할 수 있습니다.

이 전 자바스크립트에서는 callback을 이용한 비동기를 만들었지만,
callback의 깊이가 조금만 깊어져도 코드가 지저분해지는 등의 문제점으로 인해
Promise가 등장했습니다.
Promise는 비동기를 위한 객체입니다.


1-2. 생성자

new Promise(executor)

executor는 resolve 및 reject 인수를 전달할 실행 함수입니다.

function checkLength (param) {
    return new Promise((resolve,reject)=>{
        if(param.length < 10) {
            resolve(param)    // param을 전달합니다 chain에서 .then()을 이용해 호출할 수 있습니다.
        }else{
            reject(new Error('too long'))    // error을 전달합니다 chain에서 .catch()를 이용해 호출할 수 있습니다.
        }
    })
}

checkLength는 param을 인수로 받아 Promise객체를 반환합니다.
param.length가 10미만이면
resolve(param)으로 정상적으로 전달합니다.
아닐 경우에는 Error를 너무 길다는이유와 함께 반환합니다

이런 형태의 함수들을 Promise를 통해 선택적으로 연결 할 수 있습니다.

1-3. 상태

초기값

Promise는 다음 중 하나의 상태를 가집니다.

  • 대기(pending): 이행하거나 거부되지 않은 초기 상태.
  • 이행(fulfilled): 연산이 성공적으로 완료됨.
  • 거부(rejected): 연산이 실패함.

기본 전달값이 아무 것도 하지 않았으면 'value'는 'undefined'입니다.

진행에 따른 상태

  • resolve () 함수가 리턴되면 'state'가 'fulfilled'로 변경되고 'value'가 resolve () 함수에 전달 된 모든 것으로 변경됩니다.
  • reject () 함수가 리턴되면 'state'가 'rejected'로 변경되고 'value'가 reject () 함수에 전달 된 모든 것으로 변경됩니다.
    • resolve()또는 reject()가 진행됐음을 settled라고 합니다.

출처 : MDN


1-4. Promise Chaining!!

직접 한 번 만들어보겠습니다.

function devideByTwo (num) {    // 2로 나눈다
    return new Promise((resolve,reject)=>{
        if(isNaN(num)){
            reject(new Error('Not a Number'))
        }else{
            resolve(num/2)
        }
    })
}
function MultiplyByThree (num) {    // 3을 곱한다
    return new Promise((resolve,reject)=>{
        if(isNaN(num)){
            reject(new Error('Not a Number'))
        }else{
            resolve(num*3)
        }
    })
}
function AddFive(num) {        // 5를 더한다
    return new Promise((resolve,reject)=>{
        if(isNaN(num)){
            reject(new Error('Not a Number'))
        }else{
            resolve(num+5)
        }
    })
}
function SubtractFour(num) {    // 4를 뺀다
    return new Promise((resolve,reject)=>{
        if(isNaN(num)){
            reject(new Error('Not a Number'))
        }else{
            resolve(num-4)
        }
    })
}
function printLog(num) {    // 로그에 출력한다.
    console.log(num)
    return new Promise((resolve,reject)=>{
        resolve(num)
    })
}

다섯 개의 함수를 만들어봤습니다. 각각 사칙연산을 하고 나머지 한 개의 함수는 로그에 출력합니다.
Promise를 이용하는 함수를 만들 때는 Promise객체를 반환해야 한다는 것을 염두하고 있어야합니다.

return값은 아래코드의 return값처럼 바꿀 수도 있습니다.

function printLog(num) {
    console.log(num)
    return Promise.resolve(num)     // 이 부분
}

Chaining 해보기

const fifteen = 15
AddFive(15)                // 15+5
.then(MultiplyByThree)    // 20*3
.then(devideByTwo)        // 60/2
.then(SubtractFour)        // 30-4
.then(AddFive)            // 26+5
.then(printLog)        // 31
.catch(err => console.log(err))

Promise는 두 개의 인수 resolve()와 reject()를 전달받고, 코드가 의도대로 동작됐을 때 resolve()가 실행됩니다. resolve()가 호출되면 then()메서드에 전달된 함수가 실행됩니다.

확실히 Promise의 then으로 Chaining하게되면 보기가 편합니다.
여기에서는 숫자를 단순하게 사칙연산을 수행하는 Promise를 만들어봤지만
각각의 함수가 다른역할을 수행하고 Chaining으로 연결할 수 있다는점, 순서가 지켜진다는 점이 장점입니다
.then(함수)의 순서를 임의로 바꿔서 필요할때마다 적용할 수 있습니다.


JS에서의 작동원리

지난 게시물에서 자바스크립트는 싱글스레드로 컨텍스트를 Stack구조로 관리한다고 했었습니다.

  1. JS엔진은 Promise객체를 발견하면 스택의 제일 위로 이동하여 객체를 생성하고 callback을 실행합니다.
  2. callback함수는 즉시실행되며 callback함수가 값이 반환되는 것을 기다리는 동안 JS엔진의 API container로 이동합니다.
  3. 대기를 하다가 resolve() 또는 reject()둘 중 하나가 리턴되면 JS엔진의 이벤트 큐로 전송되고 스택에서 지워집니다.
  4. 큐에서 다음 순서에 있는 경우 이벤트루프가 스택의 가장 위, 첫 번째로 전달합니다.
  5. 여기에서 resolve() 또는 reject() 함수를 실행하고 Promise객체 속성을 업데이트합니다.

콜백이 값을 반환하기를 기다리는 동안 JS 엔진의 나머지 스택은 계속 실행되기 때문에 자바 스크립트가 비동기 적으로 작동합니다.

▼나머지 스택은 계속 실행된다.

const original = Promise.resolve(33);
const cast = Promise.resolve(original);

cast.then(function(value) {            // (1)
  console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));        // (2)

//result
original === cast ? true
value: 33

(1)번 Promise메서드가 2번 log메서드보다 위에 있는데도 늦게 출력됩니다.
(1)번 메서드가 Stack에서 지워지고 이벤트큐에 갔다오는 동안 (2)번 log메서드가 출력되기 때문입니다.


읽어주셔서 감사합니다!!

profile
웹 프론트엔드, RN앱 개발자입니다.
post-custom-banner

0개의 댓글