fix(http): queue jsonp <script> tag onLoad event handler in microtask (#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
This commit is contained in:
parent
b6893d23c5
commit
39266654e6
|
@ -50,6 +50,11 @@ export abstract class JsonpCallbackContext {
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JsonpClientBackend implements HttpBackend {
|
export class JsonpClientBackend implements HttpBackend {
|
||||||
|
/**
|
||||||
|
* A resolved promise that can be used to schedule microtasks in the event handlers.
|
||||||
|
*/
|
||||||
|
private readonly resolvedPromise = Promise.resolve();
|
||||||
|
|
||||||
constructor(private callbackMap: JsonpCallbackContext, @Inject(DOCUMENT) private document: any) {}
|
constructor(private callbackMap: JsonpCallbackContext, @Inject(DOCUMENT) private document: any) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,6 +145,10 @@ export class JsonpClientBackend implements HttpBackend {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We wrap it in an extra Promise, to ensure the microtask
|
||||||
|
// is scheduled after the loaded endpoint has executed any potential microtask itself,
|
||||||
|
// which is not guaranteed in Internet Explorer and EdgeHTML. See issue #39496
|
||||||
|
this.resolvedPromise.then(() => {
|
||||||
// Cleanup the page.
|
// Cleanup the page.
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
|
@ -167,6 +176,7 @@ export class JsonpClientBackend implements HttpBackend {
|
||||||
|
|
||||||
// Complete the stream, the response is over.
|
// Complete the stream, the response is over.
|
||||||
observer.complete();
|
observer.complete();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// onError() is the error callback, which runs if the script returned generates
|
// onError() is the error callback, which runs if the script returned generates
|
||||||
|
|
|
@ -45,6 +45,16 @@ const SAMPLE_REQ = new HttpRequest<never>('JSONP', '/test');
|
||||||
runOnlyCallback(home, {data: 'This is a test'});
|
runOnlyCallback(home, {data: 'This is a test'});
|
||||||
document.mockLoad();
|
document.mockLoad();
|
||||||
});
|
});
|
||||||
|
// Issue #39496
|
||||||
|
it('handles a request with callback call wrapped in promise', done => {
|
||||||
|
backend.handle(SAMPLE_REQ).subscribe(() => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
runOnlyCallback(home, {data: 'This is a test'});
|
||||||
|
});
|
||||||
|
document.mockLoad();
|
||||||
|
});
|
||||||
it('handles an error response properly', done => {
|
it('handles an error response properly', done => {
|
||||||
const error = new Error('This is a test error');
|
const error = new Error('This is a test error');
|
||||||
backend.handle(SAMPLE_REQ).pipe(toArray()).subscribe(undefined, (err: HttpErrorResponse) => {
|
backend.handle(SAMPLE_REQ).pipe(toArray()).subscribe(undefined, (err: HttpErrorResponse) => {
|
||||||
|
|
Loading…
Reference in New Issue