Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

More tasks executed then were scheduled error when xhrrequest a invalid url. #530

Closed
JiaLiPassion opened this issue Dec 8, 2016 · 6 comments

Comments

@JiaLiPassion
Copy link
Collaborator

JiaLiPassion commented Dec 8, 2016

The issue can be described as following case.

          var req = new XMLHttpRequest();
          req.open('get', 'file:///test', true);
          req.send();
        

the demo is in this plunkerplunker demo

When the open url is invalid or cors disallowed, the "More tasks executed then were scheduled" will be thrown, it may related to issue #287, and the reason is
https://github.com/angular/zone.js/blob/master/lib/browser/browser.ts#L77,
when request to a invalid url ,the browser will cancel the request and call https://github.com/angular/zone.js/blob/master/lib/browser/browser.ts#L69 immediately, it will become a sync call, so the updateTaskcount (macroTask +1) will not be called.

@RicardoVaranda
Copy link

Can confirm having this issue recently also.

@myquery
Copy link

myquery commented Mar 12, 2017

@mhevery i made changes to browser.ts, though seem not find a test/browser/XMLHttpRequest.spec.ts. but error still persist. any work around?

@JiaLiPassion
Copy link
Collaborator Author

@myquery , can you provide more details? a reproduce repo will help. and what the changes you made to browser.ts?

@myquery
Copy link

myquery commented Mar 13, 2017

`/**

  • @license
  • Copyright Google Inc. All Rights Reserved.
  • Use of this source code is governed by an MIT-style license that can be
  • found in the LICENSE file at https://angular.io/license
    */

import {patchTimer} from '../common/timers';
import {patchClass, patchMethod, patchPrototype, zoneSymbol} from '../common/utils';

import {propertyPatch} from './define-property';
import {eventTargetPatch} from './event-target';
import {propertyDescriptorPatch} from './property-descriptor';
import {registerElementPatch} from './register-element';

const set = 'set';
const clear = 'clear';
const blockingMethods = ['alert', 'prompt', 'confirm'];
const _global = typeof window === 'object' && window || typeof self === 'object' && self || global;

patchTimer(_global, set, clear, 'Timeout');
patchTimer(_global, set, clear, 'Interval');
patchTimer(_global, set, clear, 'Immediate');
patchTimer(_global, 'request', 'cancel', 'AnimationFrame');
patchTimer(_global, 'mozRequest', 'mozCancel', 'AnimationFrame');
patchTimer(_global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');

for (var i = 0; i < blockingMethods.length; i++) {
var name = blockingMethods[i];
patchMethod(_global, name, (delegate, symbol, name) => {
return function(s: any, args: any[]) {
return Zone.current.run(delegate, _global, args, name);
};
});
}

eventTargetPatch(_global);
propertyDescriptorPatch(_global);
patchClass('MutationObserver');
patchClass('WebKitMutationObserver');
patchClass('FileReader');
propertyPatch();
registerElementPatch(_global);

// Treat XMLHTTPRequest as a macrotask.
patchXHR(_global);

const XHR_TASK = zoneSymbol('xhrTask');
const XHR_SYNC = zoneSymbol('xhrSync');
const XHR_LISTENER = zoneSymbol('xhrListener');
const XHR_SCHEDULED = zoneSymbol('xhrScheduled');

interface XHROptions extends TaskData {
target: any;
args: any[];
aborted: boolean;
}

function patchXHR(window: any) {
function findPendingTask(target: any) {
var pendingTask: Task = target[XHR_TASK];
return pendingTask;
}

function scheduleTask(task: Task) {
self[XHR_SCHEDULED] = false;
var data = task.data;
//data.target.addEventListener('readystatechange', () => {
// remove existing event listener
var listener = data.target[XHR_LISTENER];
if (listener) {
data.target.removeEventListener('readystatechange', listener);
}
var newListener = data.target[XHR_LISTENER] = () => {
if (data.target.readyState === data.target.DONE) {
if (!data.aborted && self[XHR_SCHEDULED]) {
task.invoke();
}
}
//});
};
data.target.addEventListener('readystatechange', newListener);
var storedTask: Task = data.target[XHR_TASK];
if (!storedTask) {
data.target[XHR_TASK] = task;
}
sendNative.apply(data.target, data.args);
self[XHR_SCHEDULED] = true;
return task;
}

function placeholderCallback() {}

function clearTask(task: Task) {
var data = task.data;
// Note - ideally, we would call data.target.removeEventListener here, but it's too late
// to prevent it from firing. So instead, we store info for the event listener.
data.aborted = true;
return abortNative.apply(data.target, data.args);
}

var openNative =
patchMethod(window.XMLHttpRequest.prototype, 'open', () => function(self: any, args: any[]) {
self[XHR_SYNC] = args[2] == false;
return openNative.apply(self, args);
});

var sendNative =
patchMethod(window.XMLHttpRequest.prototype, 'send', () => function(self: any, args: any[]) {
var zone = Zone.current;
if (self[XHR_SYNC]) {
// if the XHR is sync there is no task to schedule, just execute the code.
return sendNative.apply(self, args);
} else {
var options: XHROptions =
{target: self, isPeriodic: false, delay: null, args: args, aborted: false};
return zone.scheduleMacroTask(
'XMLHttpRequest.send', placeholderCallback, options, scheduleTask, clearTask);
}
});

var abortNative = patchMethod(
window.XMLHttpRequest.prototype, 'abort',
(delegate: Function) => function(self: any, args: any[]) {
var task: Task = findPendingTask(self);
if (task && typeof task.type == 'string') {
// If the XHR has already completed, do nothing.
if (task.cancelFn == null) {
return;
}
task.zone.cancelTask(task);
}
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no task
// to cancel. Do nothing.
});
}

/// GEO_LOCATION
if (_global['navigator'] && _global['navigator'].geolocation) {
patchPrototype(_global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
}
/**

  • @license
  • Copyright Google Inc. All Rights Reserved.
  • Use of this source code is governed by an MIT-style license that can be
  • found in the LICENSE file at https://angular.io/license
    */

import {patchTimer} from '../common/timers';
import {patchClass, patchMethod, patchPrototype, zoneSymbol} from '../common/utils';

import {propertyPatch} from './define-property';
import {eventTargetPatch} from './event-target';
import {propertyDescriptorPatch} from './property-descriptor';
import {registerElementPatch} from './register-element';

const set = 'set';
const clear = 'clear';
const blockingMethods = ['alert', 'prompt', 'confirm'];
const _global = typeof window === 'object' && window || typeof self === 'object' && self || global;

patchTimer(_global, set, clear, 'Timeout');
patchTimer(_global, set, clear, 'Interval');
patchTimer(_global, set, clear, 'Immediate');
patchTimer(_global, 'request', 'cancel', 'AnimationFrame');
patchTimer(_global, 'mozRequest', 'mozCancel', 'AnimationFrame');
patchTimer(_global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');

for (var i = 0; i < blockingMethods.length; i++) {
var name = blockingMethods[i];
patchMethod(_global, name, (delegate, symbol, name) => {
return function(s: any, args: any[]) {
return Zone.current.run(delegate, _global, args, name);
};
});
}

eventTargetPatch(_global);
propertyDescriptorPatch(_global);
patchClass('MutationObserver');
patchClass('WebKitMutationObserver');
patchClass('FileReader');
propertyPatch();
registerElementPatch(_global);

// Treat XMLHTTPRequest as a macrotask.
patchXHR(_global);

const XHR_TASK = zoneSymbol('xhrTask');
const XHR_SYNC = zoneSymbol('xhrSync');
const XHR_LISTENER = zoneSymbol('xhrListener');
const XHR_SCHEDULED = zoneSymbol('xhrScheduled');

interface XHROptions extends TaskData {
target: any;
args: any[];
aborted: boolean;
}

function patchXHR(window: any) {
function findPendingTask(target: any) {
var pendingTask: Task = target[XHR_TASK];
return pendingTask;
}

function scheduleTask(task: Task) {
self[XHR_SCHEDULED] = false;
var data = task.data;
//data.target.addEventListener('readystatechange', () => {
// remove existing event listener
var listener = data.target[XHR_LISTENER];
if (listener) {
data.target.removeEventListener('readystatechange', listener);
}
var newListener = data.target[XHR_LISTENER] = () => {
if (data.target.readyState === data.target.DONE) {
if (!data.aborted && self[XHR_SCHEDULED]) {
task.invoke();
}
}
//});
};
data.target.addEventListener('readystatechange', newListener);
var storedTask: Task = data.target[XHR_TASK];
if (!storedTask) {
data.target[XHR_TASK] = task;
}
sendNative.apply(data.target, data.args);
self[XHR_SCHEDULED] = true;
return task;
}

function placeholderCallback() {}

function clearTask(task: Task) {
var data = task.data;
// Note - ideally, we would call data.target.removeEventListener here, but it's too late
// to prevent it from firing. So instead, we store info for the event listener.
data.aborted = true;
return abortNative.apply(data.target, data.args);
}

var openNative =
patchMethod(window.XMLHttpRequest.prototype, 'open', () => function(self: any, args: any[]) {
self[XHR_SYNC] = args[2] == false;
return openNative.apply(self, args);
});

var sendNative =
patchMethod(window.XMLHttpRequest.prototype, 'send', () => function(self: any, args: any[]) {
var zone = Zone.current;
if (self[XHR_SYNC]) {
// if the XHR is sync there is no task to schedule, just execute the code.
return sendNative.apply(self, args);
} else {
var options: XHROptions =
{target: self, isPeriodic: false, delay: null, args: args, aborted: false};
return zone.scheduleMacroTask(
'XMLHttpRequest.send', placeholderCallback, options, scheduleTask, clearTask);
}
});

var abortNative = patchMethod(
window.XMLHttpRequest.prototype, 'abort',
(delegate: Function) => function(self: any, args: any[]) {
var task: Task = findPendingTask(self);
if (task && typeof task.type == 'string') {
// If the XHR has already completed, do nothing.
if (task.cancelFn == null) {
return;
}
task.zone.cancelTask(task);
}
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no task
// to cancel. Do nothing.
});
}

/// GEO_LOCATION
if (_global['navigator'] && _global['navigator'].geolocation) {
patchPrototype(_global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
}
`
this is my whole browser.ts file which contains changes made according @mhevery guide. @JiaLiPassion Please note that this error: More tasks executed then were scheduled, is throw when i try to make a http call to nodejs from ionic 2

@paqogomez
Copy link

I'm running into this error on ionic. Could we also note that it should be "THAN were scheduled"? The typo/bad grammar makes the code very easy to find and the error easy to search for, but....

@JiaLiPassion
Copy link
Collaborator Author

@paqogomez , could you provide a reproduce repo?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants