yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆

[node js/javascript/typescript] promise를 반환하는 배열을 값을 반환하는 배열로 만들기 본문

적어보자 에러 일지

[node js/javascript/typescript] promise를 반환하는 배열을 값을 반환하는 배열로 만들기

yehey 2021. 9. 28. 00:45

오늘의 에러

javascript 정확히 말하면 typescript 프로젝트를 진행하던 중 만나서 시간을 좀 많이 투자한 에러다.

특정 배열을 map 을 이용해서 새로운 배열로 생성했는데, map 안에서 비동기 함수를 사용했고 그 비동기 함수의 반환으로 이루어진 배열이 내가 필요해하던 배열이었다.

그런데 나는 값이 필요하지, Promise <pending> 들이 필요한건 아니었다. 근데 promise pending, 즉 초기상태로 아직 이행중이거나 시작을 하지 않아서 값이 없는 상태로 여기에 이제 값을 넣을거라는 약속 Promise를 주는 것이었다.

그래서 첫번째로 내가 await 해야하는 어딘가에 await을 하지 않은건가 라는 합리적인 의심을 하며 시간을 계속 보냈다.

진작 구글링을 이때부터 했어야했는데

이곳 저곳 await이 필요한 것 같은 곳에 붙여보고, 지워보고 콘솔로 찍어도 봤지만 map 외의 다른 곳에서는 모두 잘 작동하고 있었다.

문제의 map이 쓰인 코드를 보자

처음에는 getResult 가 async await function이어서 getResult 앞에 await를 붙이고 이것저것 해 봤는데 결과는 똑같았다.

항상 resultArray에는 Promise가 담기거나 아니면 다른 곳을 잘못 건드려서 빈 배열이 출력되었다.

그래서 다시 천천히 console.log로 디버깅을 시작했음

그리고 힌트를 얻은 곳!

바로바로 const result를 console.log 로 찍었을 때, 내가 원하는 값들이 터미널 상에서는 출력되기 시작했다.

처음에는 바로 return getResult(id) 를 했기 때문에 첫 디버깅에서는 찾지 못했던 것 같다.

그러면 getResult가 잘 실행된다는 건데, 왜 resultArray는 값이 아닌 promise 로 채워져서 나올까???

내가 생각한 해답은 다음과 같음

result 결과가 값으로 채워지기 전에 getResult는 비동기로 Promise를 우선 반환한다. 따라서 result에는 이미 Promise들이 한번에 채워지고 여기에 값이 업데이트 되기 전에 resultArray 반환이 더 먼저 이루어져서 resultArray에는 값이 하나도 채워지지 않고 출력이 되는것

즉 다음과 같은 상태였다고 추측했음

어찌되었든 result에 비동기 함수가 이행된 값들이 들어가기 전에는 resultArray를 출력하지 못하도록 막아야한다.

검색 결과 여러가지 방법이 있는데 Promise.all, Promise.allSettled 등 다양한 Promise method 중 상황에 맞는 적절한 함수를 사용하면 된다.

참고하면 좋은 페이지 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

 

Promise - JavaScript | MDN

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

developer.mozilla.org

내가 고민한 것은 두가지 메서드로 Promise.all 과 allSettled다.

처음에는 한국어로 찾아봐서 Promise.all 만 있었는데, 이는 모든 Promise가 해결될 때만, 성공했을 때만 해결이 되고 그렇지 않은 경우에는 하나라도 reject 되면 함께 reject 된다.

하지만 내가 작성한 코드에는 reject가 혹시라도 될 수도 있고, map으로 처리하는 비동기 함수는 적어도 테스트에서만 90개, 앞으로 쓰일 때에는 그 이상이 될 수 있는데, 이 중 하나라도 reject 되었을 때 Promise.all 자체가 reject 되는 것은 위험하다고 판단했다.

그래서 나는 Promise.allSettled를 사용했다.

allSettled는 절대(절대인지 아닌지는 모르겠지만, 절대라고 하니까) reject하지 않고, 각각의 결과 (resolve 혹은 reject)여도 모두 수용하고 status와 value를 딕셔너리로 함께 전달한다.

 

그래서 해결된 코드는 다음과 같음

9번째 줄은 개수가 너무 많아서 array가 잘 출력되었는지 확인차 넣은 디버깅 코드로 무시해도 괜찮음

위처럼 코드를 수정하니 resultArray가 json으로 출력되는 데 시간이 더 오래걸렸지만 그래도 다음과 같이 보고싶었던 결과를 볼 수 있어서 행복했다.

와 진짜 길고 별로다. 아무튼 서버에서 전달했을 때도 결과값으로 잘 출력되었다. 굳굳~

Comments