
비동기함수 공부하다가 아래와 같은 예시를 봤다!
function increase(number){
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const result = number + 10;
if (result > 50){
const e = new Error('NumberTooBig');
return reject(e);
}
resolve(result); //왜 return을 안했지?
}, 1000);
});
return promise;
}
위 코드를 보면 setTimeout(함수) 에 들어가는 함수에서 reject(e) 는 return 문을 사용한 반면 resolve(result) 는 return문을 사용하지 않은 것을 확인할 수 있다. GPT에 물어보니 resolve(result) 이 return resolve(result) 똑같이 작동한다고 한다. 그러나 return 문을 사용한 쪽이 코드 스타일과 가독성 측면에서 더 맞다고 한다.
여기서 든 깨달음! 그러고 보니 javascript 함수에선 return문이 꼭 필요하지 않구나!
다시 GPT에 물어보니 return문을 쓰고 안쓰고는 선택이라고 한다. 단 return 문이 없으면 함수를 끝까지 읽고 (실행하고) 자동으로 return값이 undefined가 된다고 한다.
The use of return in a function depends entirely on the specific needs of that function:
- If you need the function to provide a value to the rest of your program, use a return statement.
- If the function is meant to perform a task without needing to send a value back, a return statement is not necessary.
근데 해당 예제에서는 예외인게 Promise 객체는 return 값이 없더라도 실행함수 내에서 resolve/reject가 불리면 Promise 객체의 상태가 변하고 Promise 객체 상태 값에 따라 Promise 객체는 resolve 한 결과 값 또는 에러 객체의 handle이 된다. (이 핸들은 .then, .catch 와 같은 handler에 의해 다뤄진다.)
In our example, the variable promise (=handle) holds this promise object. When you return promise from the function increase, any other part of your code that calls increase can use this "handle" to perform further actions based on the outcome of the asynchronous operation.
increase(40)
.then(result => console.log("Result:", result))
.catch(error => console.error("Error:", error));
In this snippet, the returned promise from increase(40) is used to attach .then and .catch handlers. These handlers are set to execute when the promise resolves or rejects.
Promise 가 가질 수 있는 상태는
promise is switched either fulfilled or rejected eventually. A promise in JavaScript can indeed remain in a pending state indefinitely. Promises that stay forever in a pending state generally indicate an issue in the program's logic — a situation that should usually be avoided because it can lead to memory leaks and unresponsive behavior in your applications.⚠️ resolve 나 reject 둘 다 불리지 않아도 runtime error는 안나지만 logical error 에 해당하니 둘 중 하나는 꼭 불러야 한다.
Promise의 작동 과정을 풀어서 설명하자면
Initialization of the Promise:
프로미스 객체가 new Promise(실행함수)로 생성되면 프로미스는 pending state가 된다.
Setting the Promise Value:
Promise 생성시 불린 실행함수가 resolve로 return 하느냐 reject로 return 하느냐에 따라서 fulfilled 또는 reject로 state이 바뀐다.
Using the Promise:
When you use the increase function, you can handle the resolved value using .then:
// If the promise is fulfilled,
// the code inside the .then block will
// execute using the value provided by resolve.
increase(40).then(result => {
console.log(result); // This will log 50, because 40 + 10 = 50
}).catch(error => {
console.log(error.message);
});
Or you handle error using .catch:
// If the promise is rejected,
// the code inside the .catch block will
// execute using the error object provided by reject.
increase(45).catch(error => {
console.log(error.message); // This will log 'NumberTooBig'
});
위에서 resolve 와 reject가 둘 다 불리지 않는다면 logical error라는 것을 설명했는데 반대로 만약 resolve 와 reject가 둘 다 불렸을 때 과연 const promise 객체는 무엇이 될까?
function increase(number){
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const result = number + 10;
if (result > 50){
const e = new Error('NumberTooBig');
reject(e); // return 문이 없어서 이 아래에 line도 실행된다.
}
resolve(result);
}, 1000);
});
return promise;
}
In conclusion, the final state of the promise variable will become "rejected". In JavaScript Promises, once a promise is settled (either resolved or rejected), any further calls to resolve or reject within the same promise are ignored. A promise's state is meant to be immutable once settled; it can either stay in a pending state or change to either fulfilled or rejected, but once changed, it cannot be altered again.
resolve 를 여러번 불렀을 경우에도 같은 논리로 처음 promise의 state 바꾼 (=제일 먼저 실행된) 그 resolve 의 return 값만 취급된다.
요약하자면...
- ✅ A promise can only be settled once (either resolved or rejected).
- ✅ After the first resolve or reject call, all subsequent calls are ignored.