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

feat(core): add runOutsideOfZone ability #1138

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions lib/browser/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
task.invoke();
}
}
});
}, true);

const abortNative =
patchMethod(XMLHttpRequestPrototype, 'abort', () => function(self: any, args: any[]) {
Expand All @@ -244,13 +244,12 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
return;
}
task.zone.cancelTask(task);
} else if ((Zone.current as any)[fetchTaskAborting] === true) {
// the abort is called from fetch polyfill, we need to call native abort of XHR.
return abortNative!.apply(self, args);
return;
}
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no
// task
// to cancel. Do nothing.
// task to cancel. But we need to use abortNative to abort the XHR in case the send
// is called outside of Zone.
return abortNative!.apply(self, args);
});
}
});
Expand Down
2 changes: 1 addition & 1 deletion lib/browser/webapis-media-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Zone.__load_patch('mediaQuery', (global: any, Zone: ZoneType, api: _ZonePrivate)
} else {
return delegate.apply(self, args);
}
});
}, true);
}

function patchRemoveListener(proto: any) {
Expand Down
2 changes: 1 addition & 1 deletion lib/browser/webapis-resize-observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Zone.__load_patch('ResizeObserver', (global: any, Zone: any, api: _ZonePrivate)
targets.push(target);
target[resizeObserverSymbol] = Zone.current;
return delegate.apply(self, args);
});
}, true);

api.patchMethod(
ResizeObserver.prototype, 'unobserve', (delegate: Function) => (self: any, args: any[]) => {
Expand Down
44 changes: 37 additions & 7 deletions lib/common/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,9 @@ export function patchEventTarget(
return function() {
const target = this || _global;
let delegate = arguments[1];
if (!delegate) {
// if handler is not available or we are in root zone
// use nativeListener
if (!delegate || Zone.current === Zone.root) {
return nativeListener.apply(this, arguments);
}

Expand Down Expand Up @@ -488,6 +490,10 @@ export function patchEventTarget(
}

proto[REMOVE_EVENT_LISTENER] = function() {
const delegate = arguments[1];
if (!delegate) {
return nativeRemoveEventListener.apply(this, arguments);
}
const target = this || _global;
const eventName = arguments[0];
const options = arguments[2];
Expand All @@ -503,11 +509,6 @@ export function patchEventTarget(
capture = options ? !!options.capture : false;
}

const delegate = arguments[1];
if (!delegate) {
return nativeRemoveEventListener.apply(this, arguments);
}

if (validateHandler &&
!validateHandler(nativeRemoveEventListener, delegate, target, arguments)) {
return;
Expand Down Expand Up @@ -553,11 +554,32 @@ export function patchEventTarget(

const listeners: any[] = [];
const tasks = findEventTasks(target, eventName);
const invokes: any[]|null = nativeListeners ? [] : null;

for (let i = 0; i < tasks.length; i++) {
const task: any = tasks[i];
let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
listeners.push(delegate);
if (invokes) {
invokes.push(task.invoke);
}
}
if (nativeListeners) {
const natives = nativeListeners.apply(this, arguments);
if (natives && invokes) {
natives.forEach((n: any) => {
let found = false;
for (let i = 0; i < invokes.length; i++) {
if (invokes[i] === n) {
found = true;
break;
}
}
if (!found) {
listeners.push(n);
}
});
}
}
return listeners;
};
Expand All @@ -580,8 +602,12 @@ export function patchEventTarget(
this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);
}
}
// remove removeListener listener finally
// call native again in case some event handler was not
// use patched version of addListener
this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
if (nativeRemoveAllListeners) {
nativeRemoveAllListeners.call(this);
}
} else {
const symbolEventNames = zoneSymbolEventNames[eventName];
if (symbolEventNames) {
Expand Down Expand Up @@ -609,6 +635,10 @@ export function patchEventTarget(
}
}
}

if (nativeRemoveAllListeners) {
nativeRemoveAllListeners.call(this, eventName);
}
}

if (returnTarget) {
Expand Down
6 changes: 5 additions & 1 deletion lib/common/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
}
const placeholder = function() {};
global['fetch'] = function() {
// if in root zone, just use native fetch directly.
if (Zone.current === Zone.root) {
return fetch.apply(this, arguments);
}
const args = Array.prototype.slice.call(arguments);
const options = args.length > 1 ? args[1] : null;
const signal = options && options.signal;
Expand Down Expand Up @@ -97,4 +101,4 @@ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
}
});
};
});
});
2 changes: 1 addition & 1 deletion lib/common/timers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function patchTimer(window: any, setName: string, cancelName: string, nam
// cause an error by calling it directly.
return delegate.apply(window, args);
}
});
}, true);

clearNative =
patchMethod(window, cancelName, (delegate: Function) => function(self: any, args: any[]) {
Expand Down
11 changes: 8 additions & 3 deletions lib/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ export function setShouldCopySymbolProperties(flag: boolean) {
export function patchMethod(
target: any, name: string,
patchFn: (delegate: Function, delegateName: string, name: string) => (self: any, args: any[]) =>
any): Function|null {
any,
checkInZone = false): Function|null {
let proto = target;
while (proto && !proto.hasOwnProperty(name)) {
proto = ObjectGetPrototypeOf(proto);
Expand All @@ -409,6 +410,10 @@ export function patchMethod(
if (isPropertyWritable(desc)) {
const patchDelegate = patchFn(delegate!, delegateName, name);
proto[name] = function() {
// if we are in root zone, just use native delegate.
if (checkInZone && Zone.current === Zone.root && delegate) {
return delegate.apply(this, arguments);
}
return patchDelegate(this, arguments as any);
};
attachOriginToPatched(proto[name], delegate);
Expand Down Expand Up @@ -449,7 +454,7 @@ export function patchMacroTask(
// cause an error by calling it directly.
return delegate.apply(self, args);
}
});
}, true);
}

export interface MicroTaskMeta extends TaskData {
Expand Down Expand Up @@ -480,7 +485,7 @@ export function patchMicroTask(
// cause an error by calling it directly.
return delegate.apply(self, args);
}
});
}, true);
}

export function attachOriginToPatched(patched: Function, original: any) {
Expand Down
10 changes: 7 additions & 3 deletions lib/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ interface _ZonePrivate {
patchMethod:
(target: any, name: string,
patchFn: (delegate: Function, delegateName: string, name: string) =>
(self: any, args: any[]) => any) => Function | null;
(self: any, args: any[]) => any,
checkInZone?: boolean) => Function | null;
bindArguments: (args: any[], source: string) => any[];
}

Expand Down Expand Up @@ -710,7 +711,6 @@ const Zone: ZoneType = (function(global: any) {
return this._name;
}


private _parent: Zone|null;
private _name: string;
private _properties: {[key: string]: any};
Expand Down Expand Up @@ -752,6 +752,9 @@ const Zone: ZoneType = (function(global: any) {
const _callback = this._zoneDelegate.intercept(this, callback, source);
const zone: Zone = this;
return function() {
if (zone === rootZone) {
return _callback.apply(this, arguments);
}
return zone.runGuarded(_callback, (this as any), <any>arguments, source);
} as any as T;
}
Expand Down Expand Up @@ -1352,7 +1355,8 @@ const Zone: ZoneType = (function(global: any) {
}
},
};
let _currentZoneFrame: _ZoneFrame = {parent: null, zone: new Zone(null, null)};
const rootZone = new Zone(null, null);
let _currentZoneFrame: _ZoneFrame = {parent: null, zone: rootZone};
let _currentTask: Task|null = null;
let _numberOfNestedTaskFrames = 0;

Expand Down