210821 "Zone.js has detected that ZoneAwarePromise (window|global).Promise has been overwritten

디버깅 결과 페이지

이번 포스팅에서는 현재 서비스 중인 Angular web app이 iOS 모바일 단말기에서 정상적으로 동작하지 않는 문제에 대해서 작성해보려고 한다.

[Issue]

브라우저에서 디버깅해본 결과, 위의 ERROR를 확인할 수 있었다.
현재 Promise polyfill과 zone.js가 로드되는 과정에서 문제가 되고 있다. 프로젝트 내에서는 zone.js가 로드된 다음에 Promise polyfill가 로드되고 있지만, 이 문제를 해결하기 위해서는 Promise polyfill이 로드된 다음에 zone.js가 로드되어야 한다.
그 이유는 Zone.js의 ZoneAwarePromise가 다음에 로드된 Promise polyfill에 의해 Overwritten되기 때문이다.

[Solution]

현재 프론트엔드 프로젝트의 src/polyfills.ts의 코드를 보면, import 'zone.js/dist/zone'; statement를 확인 할 수 있다. Promise polyfill 다음으로 zone.js를 로드하기 위해서는 앞서 언급한 statement를 main.js로 이전해서 작성해줘야 한다.

(위의 Solution을 적용한 뒤에 정상적으로 동작을 하는지 확인이 필요)

[Promise polyfills과 zone.js의 역할]

Promise polyfills

비동기 코드의 장점을 살리면서 콜백지옥(callback hell)을 피하기 위해 ES6 표준 spec에 포함되어있는 Promise 패턴을 사용한다. 이 Promise polyfill을 사용해서 Promise가 지원되지 않는 브라우저에서 사용될 수 있도록 해야한다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

zone.js(Zones)

Zones는 Angular의 Change Detection을 위해 중요한 역할을 한다. Angular에서는 click, change, input, submit과 같은 사용자에 의한 이벤트XMLHttpRequest를 통한 원격 서버로부터의 데이터 취득, setTimeout과 setInterval을 통해 앱의 상태를 변화시키고 있다.
Angular에서는 화면을 업데이트하는데 위와 같은 비동기 처리를 사용하고, 로직이 작성되어있는 ts 파일의 변수가 HTML Template에 바인딩되어 ts파일내의 변수의 값이 업데이트되었을때 Template내의 값도 같이 업데이트된다.

이처럼 별도로 프레임워크에 변화가 일어났다는 작업을 하지 않아도 Angular는 알아서 처리를 해주게 되는데, 이때 중요한 역할을 해주는 것이 바로 Zones이다.
Angular의 Zones의 onTurnDone 이벤트가 발생할때마다 전체 어플리케이션에 대해 Change Detection을 수행하게 되고, onTurnDone 이벤트는 Angular의 NgZone이 발생을 시킨다.

ref. Zones를 이용하면, 해당 Zones(JavaScript Execution context)가 실행되는 시점에서 여러 이벤트들을 hooking할 수 있다.

(자바스크립트의 실행 영역을 직접 나누는 것을 도와주기 때문에 여러가지 이벤트들을 hooking하는 것이 가능)

이러한 변화감지는 Zones 덕분에 가능한 것이다.

이처럼 Zones는 Angular가 DOM을 언제 업데이트해야 하는지 쉽게 발견할 수 있게 도와주는 역할을 한다.