티스토리 뷰


ES6

Promise



Promise 패턴은 ES6(ECMA Script 6)에 정식으로 포함되었습니다.

비동기프로래밍을 할 때, 콜백이 중첩되는 경우를 흔히 볼 수 있습니다. 중첩된 콜백은 화면 오른쪽을 뚫고 나갈 듯이 확장이 되고,

callback1(1, function () {
    callback2(2, function () {
        callback3(3, function () {
            callback4(4, function () {
                callback5(5, function() {
                    console.log("콜백지옥...!");
                });
            });
        });
    });
});

이러한 형태의 콜백지옥이 탄생하게 됩니다. Promise를 사용하여 콜백 지옥을 해결할 수 있습니다. Promise를 console.dir로 찍어본 결과는 밑에 그림과 같습니다.

console.dir(Promise)console.dir(Promise)


1. Promise 기본 형태

MDS에서는 밑에와 같이 Promise를 설명하고 있습니다.

new Promise(/* excutor */ function(resolve, reject) { } );


파마미터

excutor

A function that is passed with the arguments resolve and reject. The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object). The resolve and reject functions, when called, resolve or reject the promise respectively. The executor normally initiates some asynchronous work and then, once that completes, calls either the resolve or reject function to resolve the promise or else reject it if an error occurred.

If an error is thrown in the executor function, the promise is rejected. The return value of the executor is ignored.


짧은 영어로 해석을 하자면..

excutor는 resolve, reject를 인자로 가지는 함수이고, 즉시 실행이 됩니다. excutor은 비동기 동작을 수행하고, 완료가 된 후 동작이 이행이되면 resolve 함수를 에러가 발생하면 reject 동작을 수행합니다. 간략히.. 이정도로 해석 될 수 있을 것 같습니다. (너무 간략한가...)


Promise의 3가지 상태

pending : 초기 상태, 이행(fulfilled) 또는 거절(rejected) 되기 이전의 상태

fulfilled : 동작이 성공된 상태

rejected : 동작이 실패한 상태


Promise 예시

Promise의 간단한 예시입니다.

var square = function (flag, number) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            if (flag) {
                resolve({ result: "성공", number: number*number });
            } else {
                reject({ result: "실패" });
            }
        }, 1000);
    });
};

square(true, 2)
.then(function (result) {
    console.log(result);
}, function (error) {
    console.log(error);
});

Promise 예시Promise 예시


setTimeout은 비동기를 표현하기 위해 사용하였습니다. 



2. Promise prototype

Promise의 console.dir의 결과를 보면, Prototype에 catch와 then이 있는 것을 볼 수 있습니다.


Promise.prototype.catch(onRejected)

비동기 작업들이 연결된 상태에서 중간에 에러가 날 때를 위한 API입니다. .then(undefined, onRejected)로 이해하면 됩니다.

MDS에서는 밑에와 같이 설명하고 있습니다.

p.catch(onRejected);

p.catch(function(reason) {
    // rejected
});

onRejected

A Function called when the Promise is rejected. This function has one argument:

reason

The rejection reason.

The Promise returned by catch() is rejected if onRejected throws an error or returns a Promise which is itself rejected; otherwise, it is resolved.


간단한 예를 보면, 이해하기 쉬울 것 같습니다.

var p = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject('Uncaught Exception!');
  }, 1000);
});

p.catch(function(e) {
  console.log(e); // This is never called
});

catch 예시catch 예시


catch의 인자인 익명함수의 파라미터로 reject 에러 메시지를 출력 하는 것을 확인 할 수 있습니다.


Promise.prototype.then(onFulfilled, onRejected)

p.then(onFulfilled[, onRejected]);

p.then(function(value) {
   // fulfillment
  }, function(reason) {
  // rejection
});

onFulfilled

A Function called when the Promise is fulfilled. This function has one argument, the fulfillment value.


onRejected

A Function called when the Promise is rejected. This function has one argument, the rejection reason.


간단한 예를 들어보겠습니다.

var p1 = new Promise(function(resolve, reject) {
  resolve("Success!");
  // or
  // reject ("Error!");
});

p1.then(function(value) {
  console.log(value); // Success!
}, function(reason) {
  console.log(reason); // Error!
});

then 예시then 예시


Success!가 정상적으로 출력되는 것을 확인 할 수 있습니다.



3. Chaining

then과 catch를 이용하여 여러개의 비동기 동작을 연결 할 수 있습니다.

var square = function (flag, number) {
    return new Promise(function (resolve, reject) {
        if (flag) {
            resolve(number*number);
        } else {
            reject("실패");
        }
    });
};

square(true, 2)                               // async1
    .then(function (number) {
        console.log("First Success : " + number);
        return square(true, number);    // async2
    })
    .then(function (number) {
        console.log("Second Success : " + number);
        return square(false, number);  // async3
    })
    .catch(function (e) {
        console.log("First Fail : " + e);
        return square(true, 3);            // asyncFail1
    })
    .then(function (number) {
        console.log("Third Success : " + number);
        return square(true, number);  // async4
    })
    .catch(function (e) {
        console.log("Second Fail : " + e);
    })
    .then(function (number) {
        console.log("Complete : " + number);  //complete
    });

Chaining 예시Chaining 예시


위에 예시는 chaining 예시 입니다. 위의 코드 flow chart는 아래와 같습니다.


Chaining 순서도Chaining 순서도


초록색 선은 resolve 되었을 때, 빨간색 선은 reject 되었을 때의 흐름을 나타냅니다.



4. Methods

console.dir(Promise)에서 확인 할 수 있듯이 Promise는 all, race, reject, resole 4개의 메소드가 있습니다.


Promise.all(iterable)

Promise.all은 모든 promise의 상태가 fulfilled가 되거나 첫 rejection이 발생할 경우 동작하게 됩니다. 


모든 promise가 fullfilled 된 경우

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 100, "foo");
}); 

Promise.all([p1, p2, p3]).then(function (values) { 
    console.log(values); // [3, 1337, "foo"]
})

모든 promise가 fulfilled가 될 경우모든 promise가 fulfilled가 될 경우


어느 promise가 rejected 된 경우

var p1 = new Promise(function (resolve, reject) { 
    setTimeout(resolve, 1000, "one"); 
}); 
var p2 = new Promise(function (resolve, reject) { 
    setTimeout(resolve, 2000, "two"); 
});
var p3 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 3000, "three");
});
var p4 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 4000, "four");
});
var p5 = new Promise(function (resolve, reject) {
    reject("reject");
});

Promise.all([p1, p2, p3, p4, p5])
    .then(function (values) { 
        console.log(values);
    })
    .catch(reason => { 
        console.log(reason)
    });

rejection가 발생할 경우rejection가 발생할 경우


Promise.race(iterable)

처음으로 종료된 promise를 반환하는 메소드 입니다.

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "one"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "two"); 
});

Promise.race([p1, p2]).then(function(value) {
    console.log(value);
});

Promise.race 예시 1Promise.race 예시 1


fulfilled가 되던 rejected가 되면 먼저 종료되는 promise의 값을 나타냅니다.


fullfilled가 먼저 종료 될 경우

var p3 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 500, "four"); 
});

Promise.race([p3, p4]).then(function(value) {
    console.log(value); // "three"
}, function(reason) {
    // Not called
});

Promise.race 예시 2Promise.race 예시 2


p3는 fulfilled, p4는 rejected 되는 코드입니다. p3가 먼저 종료 되었기 때문에, p3의 값을 로그로 출력되는 것을 확인 할 수 있습니다.


rejected가 먼저 종료 될 경우

var p5 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "five"); 
});
var p6 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 100, "six");
});

Promise.race([p5, p6]).then(function(value) {
    // Not called      
}, function(reason) {
    console.log(reason); // "six"
});

Promise.race 예시 3Promise.race 예시 3


위의 코드도 마찬가지로, fulfilled, rejected 상관없이 먼저 종료된 p6의 값이 로그로 출력되는 것을 확인 할 수 있습니다.


Promise.reject(reason)

Promise의 static 함수로, rejected 된 Promise를 반환하는 메소드입니다.

var p1 = new Promise(function(resolve, reject) {
  resolve('Success');
});

p1.then(function(value) {
  console.log(value); // "Success!"
  return Promise.reject('oh, no!');
}).catch(function(e) {
  console.log(e); // "oh, no!"
});

Promise.reject 예시Promise.reject 예시


return Promise.reject로 catch가 실행 되는 것을 확인 할 수 있습니다.


Promise.resolve(value)

Promise의 static 함수로, resolved 된 Promise를 반환하는 메소드입니다.

var p1 = new Promise(function(resolve, reject) {
  resolve('Success');
});

p1.then(function(value) {
  console.log(value); // "Success!"
  return Promise.resolve('Success2!!');
}).then(function(value) {
  console.log(value); // "Success2!!"
});

Promise.resolve 예시Promise.resolve 예시


return Promise.resolve로 이어서 오는 then이 호출 된 것을 확인 할 수 있습니다.


댓글
댓글쓰기 폼