async function 에 new operator 를 사용하는 방법
tr;dl
- async가 필요한 constructor를 만들 때 return (async()=>{ .... })() 로 감싼다.
- 사용 시 await new ... 와 같이 new 앞에 await 을 붙여 사용한다.
javascript 에서는 function 을 사용자 정의 객체 타입으로 사용하여 객체 인스턴스를 사용할 수 있게 해주는 new 라는 operator가 있다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/new
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
이렇게 정의할 경우
var mycar = new Car("Eagle", "Talon TSi", 1993);
mycar와
var kenscar = new Car("Nissan", "300ZX", 1992);
kenscar는 다른 객체를 만들어서 mycar.year, kenscar.year 가 각각 다른 값을 유지할 수 있다.
개인적으로 function을 좋아하기 때문에 React도 hook이 생기고 난 다음부턴 조금씩 쓰기 시작했고 깊게 파고 들수록 함수가 가지고 있는 유연함과 강력함에 더더욱 빠져들고 있다.
최근 async/await 비동기 패턴을 자주 쓰면서 async function도 자주 사용하는데
객체 인스턴스를 사용하기 위해 new 를 사용하려고 하면 문제가 있는 것을 발견했다.
가령 아래와 같이 function scope 안에서 await를 사용하고
async function foo() {
let pubInfo = await (await fetch("https://www.cloudflare.com/cdn-cgi/trace")).text();
return {
getTrace: ()=> pubInfo
}
}
이와 같이 async function을 만들고 난 후
bar라는 변수를 new를 가지고 foo객체로 만드려고
let bar = new foo();
하면
Uncaught TypeError: foo is not a constructor
오류가 발생한다.
async 가 붙으면서 function인 foo의 new operator를 사용할 수 없다.
결국 foo 안에서 await 을 사용하려면 어떻게 해야할까?
원하는 것은 결국 constructor 에서 return 으로 반환 받는 { getTrace ... } object를 받으면 되는 것에 집중해보면
function 안의 scope을 전부 (async()=> {.... })() 와 같은 IIFE(Immediately Invoked Function Expression)로 감싸서 반환하면 어떨까?
function foo() {
return (async ()=>{
let pubInfo = await (await fetch("https://www.cloudflare.com/cdn-cgi/trace")).text();
return {
getTrace: ()=> pubInfo
}
})();
}
그러면 foo 는 new 로 instantiate 되면서 (async ()=> {})() block을 실행하면서 Promise 타입을 반환할 것이고
이를 다시 await으로 실행하면 되지 않을까?
new foo();
> Promise {<pending>}
new foo() 했을 때 Promise를 반환한다!
자 그럼 await을 붙여서 풀어보자.
bar = await new foo()
{getTrace: ƒ}
객체가 달려오는 걸 확인할 수 있다.
따라서 bar.getTrace() 를 실행해보면
bar.getTrace()
"fl=34f135
h=www.cloudflare.com
ip=....
ts=...
visit_scheme=https
uag=....
colo=ICN
http=http/2
loc=...
tls=TLSv1.3
sni=plaintext
warp=off
"
이와 같이 정상적으로 constructor 를 실행했고 그 내용까지 잘 접근하는 모습을 볼 수 있다.
요약:
- async가 필요한 constructor를 만들 때 return (async()=>{ .... })() 로 감싼다.
- 사용 시 await new ... 와 같이 new 앞에 await 을 붙여 사용한다.