Here is an example of how browser APIs could be patched to take advantage of Zone propagation.
Ideally we would not need to do this, since the browser would do this for us.
window.setTimeout = ((delegate) => {
return function (fn, delay, var_args) {
arguments[0] = Zone.current.wrap(fn, 'setTimeout');
return delegate.apply(this, arguments);
};
})(window.setTimeout);
Ideally we would not need to do this, since the Promise would do this for us. It could do this
more efficiently by storing the Zone
, and then invoking the callback using zone.run(...)
window.Promise.prototype.then = ((then) => {
return function (onResolve, onError) {
// Wrap callbacks without error handling.
arguments[0] = Zone.current.wrap(onResolve, 'Promise.then.onResolve', false);
arguments[0] = Zone.current.wrap(onError, 'Promise.then.onError', false);
return then.apply(this, arguments);
};
})(window.Promise.prototype.then);
Ideally we would not need to do this, since the browser would do this for us.
window.EventTarget.prototype.addEventListener = ((addEventListener) => {
return function (eventName, handler, capture) {
// Wrap callbacks without error handling.
arguments[1] = Zone.current.wrap(handler, 'EventTarget.addEventListener');
return addEventListener.apply(this, arguments);
};
})(window.EventTarget.prototype.addEventListener);
(Assuming that the browser / Promises propagate Zones)
In this example we have two applications on a page written with two frameworks, and we want to make sure that the right framework gets notified when the correct operation happens.
var frameworkAZone = Zone.current.fork({
name: 'frameworkA',
onInvoke: (self, parent, zone, callback, applyThis, applyArgs) => {
try {
return parent.invoke(callback, applyThis, applyArgs);
} finally {
frameworkAMayNeedRendering();
}
}
})
var frameworkBZone = Zone.current.fork({
name: 'frameworkB',
onInvoke: (self, parent, zone, callback, applyThis, applyArgs) => {
try {
return parent.invoke(callback, applyThis, applyArgs);
} finally {
frameworkBMayNeedRendering();
}
}
})
frameworkAZone.run(() => {
bootstrapApplicationA();
});
frameworkAZone.run(() => {
bootstrapApplicationB();
});
setInterval(() => {
expect(Zone.current.name, '<root>');
updateSomeThingNotPartOfApplication();
}, 100);
function bootstrapApplicationA() {
expect(Zone.current, frameworkAZone);
someDiv.addEventListener('click', (event) => {
expect(Zone.current, frameworkAZone);
setTimeout(() => {
expect(Zone.current, frameworkAZone);
new Promise().then(
expect(Zone.current, frameworkAZone);
// Set some value
model.someProperty = 'New Value';
// Expect that framework A will get notified of rendering.
)
}, 100);
});
}
function bootstrapApplicationB() {
expect(Zone.current, frameworkBZone);
someDiv.addEventListener('click', (event) => {
expect(Zone.current, frameworkBZone);
setTimeout(() => {
expect(Zone.current, frameworkBZone);
new Promise().then(
expect(Zone.current, frameworkBZone);
// Set some value
model.someProperty = 'New Value';
// Expect that framework B will get notified of rendering.
)
}, 100);
});
}