Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSONP call fails in Internet Explorer 11 and Google Maps API #39496

Closed
sebastianhaeni opened this issue Oct 29, 2020 · 5 comments
Closed

JSONP call fails in Internet Explorer 11 and Google Maps API #39496

sebastianhaeni opened this issue Oct 29, 2020 · 5 comments
Assignees
Labels
area: common/http hotlist: components team Related to Angular CDK or Angular Material P4 A relatively minor issue that is not relevant to core functions state: has PR
Milestone

Comments

@sebastianhaeni
Copy link
Contributor

🐞 bug report

Affected Package

The issue is caused by package @angular/common.

And it is related to @angular/google-maps.

Is this a regression?

I'm not sure. This is the first time for me trying to implement a JSONP call to the Google Maps API in Angular and support Internet Explorer 11.

Description

A JSONP call to the Google Maps API fails in Internet Explorer 11 while it works fine in other browsers.

I followed this guide: https://github.com/angular/components/tree/master/src/google-maps#lazy-loading-the-api

JSONP calls only fail in Internet Explorer with the Google Maps API. I tried other JSONP endpoints, and they seem to work fine.
So, if you think this is not an Angular issue, this bug needs to taken to the Google Maps API I guess.

🔬 Minimal Reproduction

I created a demo repository here: https://github.com/sebastianhaeni/angular-jsonp-bug

Unfortunately it cannot be reproduced on stackblitz because it needs a full prod build, so IE 11 can execute the JavaScript (ES5 and polyfills needed).

My hunch is that it's somehow a problem with the lifecycle of the JSONP callback function on the window object, which is maybe removed too early.

🔥 Exception or Error


Unhandled Promise rejection: ng_jsonp_callback_0 is not a function ; Zone:  ; Task: Promise.then ; Value: InvalidValueError: ng_jsonp_callback_0 is not a function undefined

🌍 Your Environment

Angular Version:


Angular CLI: 10.0.8
Node: 12.18.1
OS: darwin x64

Angular: 10.0.14
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.1000.8
@angular-devkit/build-angular     0.1000.8
@angular-devkit/build-optimizer   0.1000.8
@angular-devkit/build-webpack     0.1000.8
@angular-devkit/core              10.0.8
@angular-devkit/schematics        10.0.8
@angular/cli                      10.0.8
@ngtools/webpack                  10.0.8
@schematics/angular               10.0.8
@schematics/update                0.1000.8
rxjs                              6.5.5
typescript                        3.9.7
webpack                           4.43.0

Anything else relevant?

Specific browser version:

  • Internet Explorer 11
  • Version: 11.3986.14393.0
  • Update Versions: 11.0.210
@josephperrott josephperrott added area: common/http hotlist: components team Related to Angular CDK or Angular Material labels Oct 29, 2020
@ngbot ngbot bot added this to the needsTriage milestone Oct 29, 2020
@sebastianhaeni
Copy link
Contributor Author

The problem is that Internet Explorer 11 (and with that EdgeHTML) trigger the load event on the <script> tag when the JavaScript has been parsed and executed. Unfortunately, the Google Maps API script only calls the JSONP callback after some non-delaying promises have resolved. At that point the callback has already been removed by the load event. Other browsers such as Chrome and Safari trigger the load event after the promise has resolved.

Note: In IE 11, the Promise polyfill from the Google Maps script is used which uses setTimeout internally.

My guess is that IE and EdgeHTML add a microtask at the end of the execution queue if they see any setTimeout (even if it has no delay), whereas Chrome does not and executes the function in setTimeout synchronously.

In a local setup I tried to replace the following line:

node.addEventListener('load', onLoad);

with:

      node.addEventListener('load', event => setTimeout(() => onLoad(event)));

and after that it worked in Internet Explorer. Because with an extra setTimeout Internet Explorer will put the load event handler again after the promise resolve task that calls the callback and thus everything is executed in the correct order.

The same should probably be done for the error event handler as well.

Would you agree to such a fix?

@jelbourn jelbourn added state: has PR P4 A relatively minor issue that is not relevant to core functions labels Oct 30, 2020
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Oct 30, 2020
@jelbourn
Copy link
Member

@JiaLiPassion is there a chance this could be due to some sort of conflict with Google Map's Promise polyfill and Zone's patching for Promise?

@JiaLiPassion
Copy link
Contributor

@jelbourn , sure, I will check it.

@JiaLiPassion JiaLiPassion self-assigned this Oct 31, 2020
@JiaLiPassion
Copy link
Contributor

@sebastianhaeni, I just debug the case, and in IE11, Angular is using core-js promise as polyfill, and the microTask scheduler is MutationObserver not setTimeout, but your analysis is correct.

  1. in IE11, the script onload event is fired before Promise.then.
  2. in modern browsers, the script onload event is fired after Promise.then since they are using native promise.then as scheduler.

So I would suggest not using setTimeout, you can try using Promise.resolve().then() in onload event handler to delay the onload execution.

atscott pushed a commit that referenced this issue Nov 17, 2020
…#39512)

Before this change, when trying to load a JSONP script that calls the JSONP callback inside a
microtask, it will fail in Internet Explorer 11 and EdgeHTML. This commit changes the onLoad cleanup
to be queued after the loaded endpoint executed any potential microtask itself. This ensures that
the aforementioned browsers will first evaluate the loaded script calling the JSONP callback and
only then run the cleanup inside onLoad.

Fixes #39496

PR Close #39512
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: common/http hotlist: components team Related to Angular CDK or Angular Material P4 A relatively minor issue that is not relevant to core functions state: has PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants