반응형


Promise



기본적으로 Promise 객체 생성후 Promise 를 통해서 다음 실행 구문을 연달아 수행하는 형태

그러나 처리 되는 상황에 따라 then(then 안의 함수들) or catch(안의 함수) 를 타고 가는 구문에 차이가 생기게 된다

var p = new Promise(function (resolve, reject) {     //이걸 호출하지 않으면 then 으로 넘어가지 않는다     //resolve(2);       //성공 함수로 넘어간다     //이걸 호출하지 않으면 then 으로 넘어가지 않는다     reject(2);        //실패 함수로 넘어가게 된다 }); //then() 은 Primise 를 리턴한다 p.then(function (value) {       //성공함수     console.log(value);     return value + 1; }, function(reject) {           //실패함수     console.log(reject);     return 10; } ).then(function (value) {        //다음 함수들     console.log(value);     return value + 1; }).then(function (value) {        //다음 함수들

    console.log(value);     throw 100; }).catch(function (ff) {            //예외 함수

    console.log(ff); });


결과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
resolve(2); 일때의 결과
 
2
3
4
100
 
 
 
reject(2); 일때의 결과
 
2
10
11
100
 
cs


Promise 생성하기

Promise 오브젝트는 new 키워드와 생성자를 사용하여 만듭니다. 이 생성자는 인수로 "executor 함수"라는 함수를 사용합니다. 이 함수는 매개 변수로 두 가지 함수를 가져야 합니다. 비동기 작업이 성공적으로 완료되고 결과를 값으로 반환하면 첫 번째 함수(resolve)가 호출됩니다. 두 번째 (reject)는 작업이 실패 할 때 호출되며 보통 오류 객체를 반환합니다.

const myFirstPromise = new Promise((resolve, reject) => {
  // do something asynchronous which eventually calls either:
  //
  //   resolve(someValue); // fulfilled
  // or
  //   reject("failure reason"); // rejected
});

함수가 프로미스를 사용하도록 하려면 단순히 프로미스를 반환하면됩니다.

function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
}


예제

Link to section기본 예제

let myFirstPromise = new Promise((resolve, reject) => 
{
  // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
  // In this example, we use setTimeout(...) to simulate async code. 
  // In reality, you will probably be using something like XHR or an HTML5 API.
  setTimeout(function(){
    resolve("Success!"); // Yay! Everything went well!
  }, 3000);
});

myFirstPromise.then((successMessage) => {
  // successMessage is whatever we passed in the resolve(...) function above.
  // It doesn't have to be a string, but if it is only a succeed message, it probably will be.
  console.log("Yay! " + successMessage);
});



결과 3초 후  

"Success!"





Promise.prototype.then()



then() 메서드는 Promise를 리턴하고 두개의 콜백 함수를 인수로 받습니다. 하나는 Promise가 성공(success)했을 때를 위한 콜백 함수이고, 다른 하나는 실패(failure)했을 때를 위한 콜백 함수입니다.



구문

p.then(onFulfilled, onRejected);

p.then(function(value) {
  // 이행(fulfillment)
  }, function(reason) {
  // 거부
});

Link to section매개변수

onFulfilled
Promise가 수행될 때 호출되는 Function 이고, 수행 값(fulfillment value) 하나를 인수로 받습니다.
onRejected
Promise가 거부될 때 호출되는 Function 이고, 거부 이유(rejection reason) 하나를 인수로 받습니다.

Link to section설명

then 과 Promise.prototype.catch() 메서드는 promise 를 리턴하기 때문에, chaining 이 가능합니다. — composition 이라고도 합니다.

Link to section

Link to sectionthen 메서드 사용

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

p1.then(function(value) {
  console.log(value); // 성공!
}, function(reason) {
  console.log(reason); // 오류!
});

Link to sectionChaining

then 메서드는 Promise를 리턴하기 때문에, 이어지는 then 호출들을 손쉽게 chaining 할 수 있습니다. onFulfilled 또는 onRejected 콜백 함수가 리턴하는 값은 자동으로 resolved promise로 wrapping 되기 때문에 다음에 오는 then 이나 catch 메서드로 전달 됩니다.

var p2 = new Promise(function(resolve, reject) {
  resolve(1);
});

p2.then(function(value) {
  console.log(value); // 1
  return value + 1;
}).then(function(value) {
  console.log(value); // 2
});

p2.then(function(value) {
  console.log(value); // 1
});








다음과 같이 catch()를 사용할 수도 있습니다.

get('story.json').then(function(response) {
  console
.log("Success!", response);
}).catch(function(error) {
  console
.log("Failed!", error);
})

catch()에 대한 특별한 것은 없습니다. then(undefined, func)의 보완에 불과하지만 가독성은 훨씬 높습니다. 상기 두 코드 예시는 동일하게 동작하지 않습니다. 후자는 다음과 같습니다.

get('story.json').then(function(response) {
  console
.log("Success!", response);
}).then(undefined, function(error) {
  console
.log("Failed!", error);
})

차이는 미묘하지만 매우 유용합니다. 프라미스 거부는 거부 콜백(또는 동일하게 기능하는 catch())을 사용하여 다음 then()으로 건너뜁니다. then(func1, func2)를 사용하는 경우 func1와 func2 중에 하나만 호출되며, 둘이 동시에 호출되지 않습니다. 그러나 then(func1).catch(func2)를 사용하는 경우 둘은 체인에서 개별적인 단계이므로 func1이 거부하면 둘 다 호출됩니다. 다음을 봅시다.

asyncThing1().then(function() {
 
return asyncThing2();
}).then(function() {
 
return asyncThing3();
}).catch(function(err) {
 
return asyncRecovery1();
}).then(function() {
 
return asyncThing4();
}, function(err) {
 
return asyncRecovery2();
}).catch(function(err) {
  console
.log("Don't worry about it");
}).then(function() {
  console
.log("All done!");
})

위의 흐름은 일반 자바스크립트 try/catch와 매우 유사하며, 'try'를 사용하여 발생하는 오류는 즉시 catch() 블록으로 이동합니다. 다음은 이를 흐름도로 만든 것입니다.



프라미스 처리 시에는 청색선을 따르고 프라미스 거부 시에는 적색선을 따르면 됩니다.






new Promise, Promise.resolve()  차이


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//new Promise 패턴을 사용하면 아래와 같이 쓸 수 있습니다.
 
function async1 (param) {
    return new Promise(function(resolve, reject) {
        resolve(param*2);
    });
}
function async2 (param) {
    return new Promise(function(resolve, reject) {
        resolve(param*3);
    });
}
function async3 (param) {
    return new Promise(function(resolve, reject) {
        resolve(param*4);
    });
}
 
var start = 1;
async1(start)
    .then(async2)
    .then(async3)
    .then(result => {
        console.log(result); // 24
    });
 
 
 
 
 
//함수 선언 코드가 좀 길어지긴 했지만... 함수 사용 부분은 좀 더 명확해졌습니다.
//같은 내용을 Promise.resolve() 로 사용하면 아래와 같죠.
 
 
function async1 (param) {
    return Promise.resolve(param*2);
}
function async2 (param) {
    return Promise.resolve(param*3);
}
function async3 (param) {
    return Promise.resolve(param*4);
}
 
var start = 1;
async1(start)
    .then(async2)
    .then(async3)
    .then(result => {
        console.log(result); // 24
    });
 
 
 
//그런데 이런 상황이 존재함
 
//(이 예제는 크롬의 cross origin 제약을 해제하고 실행했습니다.)
 
function request (param) {
    return Promise.resolve()
        .then(function () {
            var xhr = new XMLHttpRequest();
 
            xhr.open('GET''http://google.co.kr/'true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    return Promise.resolve(xhr.response);
                }
            };
            xhr.send(null);
        });
}
 
Promise.resolve()
    .then(request)
    .then(result => {
        console.log('ok');
        console.log(result);
    });
 
/*
위 코드는 http://google.co.kr에 GET 요청을 보낸 뒤 받아서 결과를 텍스트로 출력하는 예제입니다.
 Promise 안에서 readyState와 status를 확인해서 Promise.resolve()를 리턴하므로 얼핏 보면 돌아갈 
 것 같습니다만... 제대로 동작하지 않습니다. 콘솔에 찍히는 result는 undefined 입니다.  */
 
 
결과는 
 
ok
undefined
 
 
 
//request() 함수에서 xhr.send() 를 실행하면 해당 컨텍스트에서의 작업은 끝나고 Promise 컨텍스트도 종료됩니다. 
//xhr이 완료되었을 때 반환하는 객체를 받을 타이밍에는 이미 이전 함수가 끝나있기 때문이죠.
 
//이 코드는 new Promise()를 써서 이렇게 바뀌어야 합니다.
 
 
 
function request (param) {
    return new Promise(function(resolve, reject) {
        var xhr = new XMLHttpRequest();
 
        xhr.open('GET''http://google.co.kr/'true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
                resolve(xhr.response);
            }
        };
        xhr.send(null);
    })
}
 
Promise.resolve()
    .then(request)
    .then(result => {
        console.log('ok');
        console.log(result);
    });
 
 
 
/*
두번째 라인에서 생성한 Promise 객체의 함수 실행 컨텍스트를 유지하기 위해 Promise.resolve() 대신 new Promise()를 사용하고 
최종 콜백 지점인 여덟번째 라인에서 resolve()를 실행해줍니다. 기존의 callback 사용 방식과 비슷하다고 보면 간단합니다.
이렇게 사용하면 Promise 실행 컨텍스트를 벗어나지 않고 원하는 결과를 얻을 수 있습니다.*/
 
 
 
 
 
 

cs



비슷하게 ajax 콜을 요청하거나 DB에서 데이터를 가져올 때와 같이 async 함수를 감싸는 경우는 new Promise()를
사용하면 됩니다.

처음 Promise를 사용할 때는 왜 같은 흐름의 함수가 두 개로 제공될까 이상했는데, 사용하다보니
return Promise.resolve()와 new Promise()는 
사용 방법이 약간 다릅니다. return Promise.resolve()는
sync 로직 흐름에서, new Promise()는 sync는 물론, async 로직 흐름에서도 사용할 수 있습니다.

요새 모듈은 사용할 때 Promise를 지원하는 경우가 종종 있습니다. 좀 더 많은 모듈이 Promise를 지원하기를 바래봅니다


ref : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
ref : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
ref : https://developers.google.com/web/fundamentals/primers/promises
ref : http://han41858.tistory.com/11


반응형

+ Recent posts