Promise 이해하기

김명성·2022년 1월 21일
0

자바스크립트

목록 보기
21/26

Promise

Promise는 자바스크립트의 비동기 처리에 사용되는 객체이다.
비동기처리란 특정 코드의 실행이 완료될 때까지 기다리지 않고
다음 코드를 먼저 수행하는 자바스크립트의 특성이다.

Promise는 서버에서 받아온 데이터를 화면에 표시할 때 주로 사용된다.
웹 APP을 구현할 때 서버에서 데이터를 요청하고 받아올 때 API를 사용하는데에 있어 필연적으로 latency가 발생된다. 자바스크립트는 스크립트의 최상단에서부터 최하단으로 코드를 실행하는데, 이때 API를 받는 latency를 기다리지 않고 바로 코드를 실행하여 오류가 발생한다. 이런 문제점을 막기 위해 (기다렸다가 실행하기 위해) Promise가 사용된다.






프로미스가 사용되는 예제 코드 1

    function promise(parameter){
        return new Promise(function(resolve,reject){

            window.setTimeout(function(){
                //parameter가 참이면
                if(parameter){
                    // Promise의 parameter resolve 호출
                    resolve("completed");
                    //parameter이 거짓이면
                }else{
                    //Promise의 parameter reject 호출
                    reject(Error("failed"));
                }
            }, 3000);
        });
}

//Promise 실행
promise(true)
.then(function(text){
    console.log(text)
}
, function(error){
    console.error(error);
});
Promise는 호출 된 이후 다음과 같은 상태가 된다.

- Pending : 대기중이거나, 함수를 수행 중인 상태.
- Fulfilled : 함수를 수행하여 Promise를 이행한 상태.
- Rejected : 네트워크 연결이나 오류로 인해 Promise를 이행하지 못한 상태.

Promise 생성

New Promise로 Promise를 생성하고 resolve,reject를 호출하기 전까지 Promise는
Pending 상태이다.
비동기 작업을 성공적으로 이행했다면 Promise는 첫번째 parameter인 resolve함수를 호출하고, 실패하면 reject 함수를 호출한다는 것이 promise의 기본 개념이다.

Promise 실행부

promise(true)
// .then을 통해 resolve일 때 호출할 함수를,콤마로 reject일 때 호출할 함수를 작성한다
.then(function(text){
    console.log(text)
}
, function(error){
    console.error(error);
});


프로미스가 사용되는 예제 코드 2.

Promise.all을 사용하는 코드

var promise1 = new Promise(function (resolve, reject) {

	// 비동기를 표현하기 위해 setTimeout 함수를 사용 
	window.setTimeout(function () {

		// 해결됨 
		console.log("첫번째 Promise 완료");
		resolve("11111");

	}, Math.random() * 20000 + 1000);
});
// 2번째 프로미스 선언
var promise2 = new Promise(function (resolve, reject) {

	// 비동기를 표현하기 위해 setTimeout 함수를 사용 
	window.setTimeout(function () {

		// 해결됨 
		console.log("두번째 Promise 완료");
		resolve("222222");

	}, Math.random() * 10000 + 1000);
});


Promise.all([promise1, promise2])
.then(function (values) {
	console.log("모두 완료됨", values);
});



프로미스가 사용되는 예제 코드 3.

Promise에서 error 발생시 catch의 활용 코드

    var _promise = function (param) {

        return new Promise(function (resolve, reject) {

            // 비동기를 표현하기 위해 setTimeout 함수를 사용 
            window.setTimeout(function () {

                // 파라메터가 참이면, 
                if (param) {

                    // 해결됨 
                    resolve("해결 완료");
                }

                // 파라메터가 거짓이면, 
                else {

                    // 실패 
                    reject(Error("실패!!"));
                }
            }, 3000);
        });
    };
    _promise(true)
        .then(JSON.parse)
        .catch(function () { 
            window.alert('체이닝 중간에 에러가!!');
        })
        .then(function (text) {
            console.log(text);
        });

위 예제로 .then의 parameter에 JSON.parse를 입력한다면 JSON이 String값을 리턴하므로 Error가 나게 된다. 따라서 다음 then으로 이동하지 못하고 catch가 받게 된다. catch는 이와 같이 연속되는 promise에서 발생하는 오류를 받아주는 역할을 한다.





부록 코드 1. catch의 쓰임새를 잘 나타내주는 코드

    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!");});


프로미스가 사용되는 예제 코드 4.

return 없이 new Promise 생성하기1

var promise = new Promise(function(resolve, reject) {
	if (+new Date()%2 === 0) {
		resolve("Stuff worked!");  
	}
	else {
		reject("It broke");
	}
});

promise.then();

위와 같이 선언할 경우 Promise 객체의 매개변수인 익명함수는 즉각 실행된다.



프로미스가 사용되는 예제 코드 5.

return 없이 new Promise 생성하기2

new Promise(function(resolve, reject) {

	// 50프로 확률로 resolve 
	if (+new Date()%2 === 0) {
		resolve("Stuff worked!");  
	}
	else {
		reject(Error("It broke"));
	}
}).then(alert).catch(alert);

프로미스 정의부에 바로 .then을 붙여 사용할수도 있다.


학습한 내용 응용 및 복습 예제 1.

function promise(parameter){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            if(parameter){
                resolve("completed");
            }else{
                reject(Error("it's failed. something wrong !"));
            }
        }, 3000);
    });
}

promise(Math.random() * 10 <= 5)
.then(function(text){
console.log(text);
}
, function(error){
console.error(error);
});


학습한 내용 응용 및 복습 예제 2.

var promise1 = new Promise(function (resolve, reject) {
	window.setTimeout(function () {
		console.log("첫번째 Promise 완료");
		resolve("11111");

	}, Math.random() * 10000 + 1000);
});
var promise2 = new Promise(function (resolve, reject) {
	window.setTimeout(function () {
        if((Math.random() *10) <= 5){
		console.log("두번째 Promise 완료");
		resolve("222222");
        }else{
            console.log("두번째 Promise에 오류가 발생했습니다.");
            reject("error Number99");
        }
	}, Math.random() * 5000 + 1000);
});

Promise.all([promise1, promise2])
.then(function (values) {
	console.log("모두 완료됨", values);
})
.catch(function(){
console.log("오류 발생. 리커버리 단계로 이동합니다.");
})
.then(function(){
    if((Math.random()*10) <= 4){
		setTimeout(function() {
            console.log("정상처리 되었습니다.")}
            , 5000);
        }else{
            setTimeout(function(){
            console.log("리커버리 실패");
            console.log("관리자에게 문의하세요.")
        },5000)
        }
});

**** 매우 중요한 점 
각 함수 내에서 Promise1 Promise2를 생성한다면 
Promise.all([promise1, promise2])형식은 사용할 수 없고
Promise.all([promise1(), promise2()])형식으로 사용해야 한다.




학습한 내용 응용 및 복습 예제 3.

var _promise = new Promise(function(resolve, reject) {
	
	// 여기에서는 무엇인가 수행 

	// 50프로 확률로 resolve 
	if (+new Date()%2 === 0) {
		resolve("Stuff worked!");  
	}
	else {
		reject(Error("It broke"));
	}
});
_promise
.then(console.log,alert);

Promise에 포함된 익명함수의 매개변수 resolve,reject는 then의 인자 값을 받아온다.
그래서 resolve 일때에는 console.log를, reject일 때에는 alert으로 알려줄 수 있게 만들었다.

학습한 내용 응용 및 복습 예제 4. Promise로 순서대로 작업하게 만들기.



    const promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            if(0 < 1){
                resolve(`1번 요원의 정보를 받아왔습니다.`)
            }
        }, 4000, 1)
        
    });
    
    const promise2 = new Promise(function(resolve,reject){
        setTimeout(function(){
            if(0 < 1){
                resolve(`2번 요원의 정보를 받아왔습니다.`)
            }
        }, 2000, 2)
        
    });
    const promise3 = new Promise(function(resolve,reject){
        setTimeout(function(){
            if(0 < 1){
                resolve(`3번 요원의 정보를 받아왔습니다.`)
            }
        }, 1000, 3)
        
    });
    
    Promise.all([promise1,promise2,promise3])
    .then(console.log)
    .then(function(value){
    console.log("정보 요청을 모두 보냈습니다.");
    console.log(`요원들의 정보를 모두 받아왔습니다.`);
    });
setTimeout을 삽입한 이유는 API를 가져올 때 생기는 latency를 대신함.
if문을 삽입한 이유는 실행 했을때 성공 또는 실패할 경우를 가정함.


함수는 정의한다고 실행되는 것이 아니고, 호출 되어야 실행된다.
이 부분을 기억하며 순서를 파악하자.

	function b() {
        console.log("b called!");
    }
    
    function a(alalnoghigoto) {
        console.log("a started!");
        alalnoghigoto();
        console.log("a ended!");
    }
    console.log(1);
    console.log(2);
    a(b); // a로 b를 끌고 간다라고 이해.
    console.log(3);
    console.log(4);
함수 a의 매개변수를 아무렇게나 지은 이유는, 매개변수의 이름은 인자 b가 들어가는 데에는 문제가 없기 때문이다. 하지만 호출할 때에는 반드시 같은 매개변수 이름으로 들어가야 한다. 여기에서 유의해야 할 점은 b가 a의 인자로 전달될 시점에도 b는 호출(실행)되지 않는다는 점이다.

출처
https://joshua1988.github.io/web-development/javascript/promise-for-beginners/
https://programmingsummaries.tistory.com/325
https://elvanov.com/2597

0개의 댓글