From ce47cfbae27f8dff1e6db1c098229e25d3d088f0 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 9 Mar 2017 18:21:26 -0800 Subject: [PATCH] chore: release v0.7.8 --- CHANGELOG.md | 33 ++ dist/async-test.js | 13 +- dist/fake-async-test.js | 8 +- dist/jasmine-patch.js | 14 +- dist/jasmine-patch.min.js | 2 +- dist/long-stack-trace-zone.js | 37 +- dist/long-stack-trace-zone.min.js | 2 +- dist/mocha-patch.js | 8 +- dist/proxy.js | 6 +- dist/sync-test.js | 6 +- dist/task-tracking.js | 6 +- dist/webapis-media-query.js | 58 ++- dist/webapis-media-query.min.js | 1 + dist/webapis-notification.js | 39 +- dist/webapis-notification.min.js | 1 + dist/wtf.js | 16 +- dist/wtf.min.js | 2 +- dist/zone-mix.js | 786 +++++++++++++++++++++--------- dist/zone-node.js | 701 ++++++++++++++++++-------- dist/zone.js | 524 ++++++++++++++------ dist/zone.js.d.ts | 52 ++ dist/zone.min.js | 2 +- package.json | 2 +- 23 files changed, 1685 insertions(+), 634 deletions(-) create mode 100644 dist/webapis-media-query.min.js create mode 100644 dist/webapis-notification.min.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dbbd3646..7f0ebc176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ + +## [0.7.8](https://github.com/angular/zone.js/compare/v0.7.6...0.7.8) (2017-03-10) + + +### Bug Fixes + +* **core:** remove debugger ([#639](https://github.com/angular/zone.js/issues/639)) ([0534b19](https://github.com/angular/zone.js/commit/0534b19)) +* **error:** fix [#618](https://github.com/angular/zone.js/issues/618), ZoneAwareError should copy Error's static propeties ([#647](https://github.com/angular/zone.js/issues/647)) ([2d30914](https://github.com/angular/zone.js/commit/2d30914)) +* **jasmine:** support "pending" `it` clauses with no test body ([96cb3d0](https://github.com/angular/zone.js/commit/96cb3d0)), closes [#659](https://github.com/angular/zone.js/issues/659) +* **minification:** fix [#607](https://github.com/angular/zone.js/issues/607) to change catch variable name to error/err ([#609](https://github.com/angular/zone.js/issues/609)) ([33d0d8d](https://github.com/angular/zone.js/commit/33d0d8d)) +* **node:** patch crypto as macroTask and add test cases for crypto, remove http patch ([#612](https://github.com/angular/zone.js/issues/612)) ([9e81037](https://github.com/angular/zone.js/commit/9e81037)) +* **package:** use fixed version typescript,clang-format and jasmine ([#650](https://github.com/angular/zone.js/issues/650)) ([84459f1](https://github.com/angular/zone.js/commit/84459f1)) +* **patch:** check timer patch return undefined ([#628](https://github.com/angular/zone.js/issues/628)) ([47962df](https://github.com/angular/zone.js/commit/47962df)) +* **patch:** fix [#618](https://github.com/angular/zone.js/issues/618), use zoneSymbol as property name to avoid name conflict ([#645](https://github.com/angular/zone.js/issues/645)) ([fcd8be5](https://github.com/angular/zone.js/commit/fcd8be5)) +* **task:** findEventTask should return Task array ([#633](https://github.com/angular/zone.js/issues/633)) ([14c7a6f](https://github.com/angular/zone.js/commit/14c7a6f)) +* **task:** fix [#638](https://github.com/angular/zone.js/issues/638), eventTask/Periodical task should not be reset after cancel in running state ([#642](https://github.com/angular/zone.js/issues/642)) ([eb9250d](https://github.com/angular/zone.js/commit/eb9250d)) +* **timers:** cleanup task reference when exception ([#637](https://github.com/angular/zone.js/issues/637)) ([2594940](https://github.com/angular/zone.js/commit/2594940)) +* **webapi:** refactor webapi to not import util.ts directly ([8b2543e](https://github.com/angular/zone.js/commit/8b2543e)), closes [#652](https://github.com/angular/zone.js/issues/652) +* **xhr:** fix [#657](https://github.com/angular/zone.js/issues/657), sometimes xhr will fire onreadystatechange with done twice ([#658](https://github.com/angular/zone.js/issues/658)) ([36c0899](https://github.com/angular/zone.js/commit/36c0899)) +* **zonespec:** don't throw and exception when setInterval is called within a async test zone ([#641](https://github.com/angular/zone.js/issues/641)) ([c07560f](https://github.com/angular/zone.js/commit/c07560f)) + + +### Features + +* add Zone.root api ([#601](https://github.com/angular/zone.js/issues/601)) ([9818139](https://github.com/angular/zone.js/commit/9818139)) +* allow tasks to be canceled and rescheduled on different zone in a zone delegate ([#629](https://github.com/angular/zone.js/issues/629)) ([76c6ebf](https://github.com/angular/zone.js/commit/76c6ebf)) +* make fetch() zone-aware without triggering extra requests or uncatchable errors. ([#622](https://github.com/angular/zone.js/issues/622)) ([6731ad0](https://github.com/angular/zone.js/commit/6731ad0)) +* **bluebird:** patch bluebird promise and treat it as microtask ([#655](https://github.com/angular/zone.js/issues/655)) ([e783bfa](https://github.com/angular/zone.js/commit/e783bfa)) +* **electron/nw:** fix [#533](https://github.com/angular/zone.js/issues/533), in electron/nw.js, we may need to patch both browser API and nodejs API, so we need a zone-mix.js to contains both patched API. ([6d31734](https://github.com/angular/zone.js/commit/6d31734)) +* **longStackTraceSpec:** handled promise rejection can also render longstacktrace ([#631](https://github.com/angular/zone.js/issues/631)) ([a4c6525](https://github.com/angular/zone.js/commit/a4c6525)) +* **promise:** fix [#621](https://github.com/angular/zone.js/issues/621), add unhandledRejection handler and ignore consoleError ([#627](https://github.com/angular/zone.js/issues/627)) ([f3547cc](https://github.com/angular/zone.js/commit/f3547cc)) + + ## [0.7.6](https://github.com/angular/zone.js/compare/v0.7.4...0.7.6) (2017-01-17) diff --git a/dist/async-test.js b/dist/async-test.js index 2f1feaad8..a417d8c6c 100644 --- a/dist/async-test.js +++ b/dist/async-test.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -61,13 +61,6 @@ var AsyncTestZoneSpec = (function () { } return false; }; - AsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, currentZone, targetZone, task) { - if (task.type == 'macroTask' && task.source == 'setInterval') { - this._failCallback('Cannot use setInterval from within an async zone test.'); - return; - } - return delegate.scheduleTask(targetZone, task); - }; AsyncTestZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) { delegate.hasTask(target, hasTaskState); if (hasTaskState.change == 'microTask') { diff --git a/dist/fake-async-test.js b/dist/fake-async-test.js index 7d0dd4d22..ce0253381 100644 --- a/dist/fake-async-test.js +++ b/dist/fake-async-test.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -98,7 +98,7 @@ return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; + args[_i - 0] = arguments[_i]; } fn.apply(global, args); if (_this._lastError === null) { diff --git a/dist/jasmine-patch.js b/dist/jasmine-patch.js index d188c8cfe..e82d31de4 100644 --- a/dist/jasmine-patch.js +++ b/dist/jasmine-patch.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -98,11 +98,11 @@ // The `done` callback is only passed through if the function expects at least one argument. // Note we have to make a function with correct number of arguments, otherwise jasmine will // think that all functions are sync or async. - return (testBody.length == 0) ? function () { - return testProxyZone.run(testBody, this); - } : function (done) { + return testBody && (testBody.length ? function (done) { return testProxyZone.run(testBody, this, [done]); - }; + } : function () { + return testProxyZone.run(testBody, this); + }); } var QueueRunner = jasmine.QueueRunner; jasmine.QueueRunner = (function (_super) { diff --git a/dist/jasmine-patch.min.js b/dist/jasmine-patch.min.js index b4695a0d2..dedbeeb83 100644 --- a/dist/jasmine-patch.min.js +++ b/dist/jasmine-patch.min.js @@ -1 +1 @@ -!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(this,function(){"use strict";!function(){function e(e){return function(){return c.run(e,this,arguments)}}function n(e){return 0==e.length?function(){return u.run(e,this)}:function(n){return u.run(e,this,[n])}}var r=function(e,n){function r(){this.constructor=e}for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)};if(!Zone)throw new Error("Missing: zone.js");if("undefined"==typeof jasmine)throw new Error("Missing: jasmine.js");if(jasmine.__zone_patch__)throw new Error("'jasmine' has already been patched with 'Zone'.");jasmine.__zone_patch__=!0;var t=Zone.SyncTestZoneSpec,o=Zone.ProxyZoneSpec;if(!t)throw new Error("Missing: SyncTestZoneSpec");if(!o)throw new Error("Missing: ProxyZoneSpec");var i=Zone.current,c=i.fork(new t("jasmine.describe")),u=null,s=jasmine.getEnv();["describe","xdescribe","fdescribe"].forEach(function(n){var r=s[n];s[n]=function(n,t){return r.call(this,n,e(t))}}),["it","xit","fit"].forEach(function(e){var r=s[e];s[e]=function(e,t,o){return arguments[1]=n(t),r.apply(this,arguments)}}),["beforeEach","afterEach"].forEach(function(e){var r=s[e];s[e]=function(e,t){return arguments[0]=n(e),r.apply(this,arguments)}});var f=jasmine.QueueRunner;jasmine.QueueRunner=function(e){function n(n){n.onComplete=function(e){return function(){u=null,i.scheduleMicroTask("jasmine.onComplete",e)}}(n.onComplete),e.call(this,n)}return r(n,e),n.prototype.execute=function(){var n=this;if(Zone.current!==i)throw new Error("Unexpected Zone: "+Zone.current.name);u=i.fork(new o),Zone.currentTask?e.prototype.execute.call(this):Zone.current.scheduleMicroTask("jasmine.execute().forceTask",function(){return f.prototype.execute.call(n)})},n}(f)}()}); \ No newline at end of file +!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(this,function(){"use strict";!function(){function e(e){return function(){return c.run(e,this,arguments)}}function n(e){return e&&(e.length?function(n){return u.run(e,this,[n])}:function(){return u.run(e,this)})}var r=function(e,n){function r(){this.constructor=e}for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)};if(!Zone)throw new Error("Missing: zone.js");if("undefined"==typeof jasmine)throw new Error("Missing: jasmine.js");if(jasmine.__zone_patch__)throw new Error("'jasmine' has already been patched with 'Zone'.");jasmine.__zone_patch__=!0;var t=Zone.SyncTestZoneSpec,o=Zone.ProxyZoneSpec;if(!t)throw new Error("Missing: SyncTestZoneSpec");if(!o)throw new Error("Missing: ProxyZoneSpec");var i=Zone.current,c=i.fork(new t("jasmine.describe")),u=null,s=jasmine.getEnv();["describe","xdescribe","fdescribe"].forEach(function(n){var r=s[n];s[n]=function(n,t){return r.call(this,n,e(t))}}),["it","xit","fit"].forEach(function(e){var r=s[e];s[e]=function(e,t,o){return arguments[1]=n(t),r.apply(this,arguments)}}),["beforeEach","afterEach"].forEach(function(e){var r=s[e];s[e]=function(e,t){return arguments[0]=n(e),r.apply(this,arguments)}});var f=jasmine.QueueRunner;jasmine.QueueRunner=function(e){function n(n){n.onComplete=function(e){return function(){u=null,i.scheduleMicroTask("jasmine.onComplete",e)}}(n.onComplete),e.call(this,n)}return r(n,e),n.prototype.execute=function(){var n=this;if(Zone.current!==i)throw new Error("Unexpected Zone: "+Zone.current.name);u=i.fork(new o),Zone.currentTask?e.prototype.execute.call(this):Zone.current.scheduleMicroTask("jasmine.execute().forceTask",function(){return f.prototype.execute.call(n)})},n}(f)}()}); \ No newline at end of file diff --git a/dist/long-stack-trace-zone.js b/dist/long-stack-trace-zone.js index 33c472a5e..f6d59a203 100644 --- a/dist/long-stack-trace-zone.js +++ b/dist/long-stack-trace-zone.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -18,6 +18,10 @@ * 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 */ +/** + * @fileoverview + * @suppress {globalThis} + */ var NEWLINE = '\n'; var SEP = ' ------------- '; var IGNORE_FRAMES = []; @@ -36,17 +40,17 @@ function getStacktraceWithCaughtError() { try { throw getStacktraceWithUncaughtError(); } - catch (e) { - return e; + catch (err) { + return err; } } // Some implementations of exception handling don't create a stack trace if the exception // isn't thrown, however it's faster not to actually throw the exception. var error = getStacktraceWithUncaughtError(); -var coughtError = getStacktraceWithCaughtError(); +var caughtError = getStacktraceWithCaughtError(); var getStacktrace = error.stack ? getStacktraceWithUncaughtError : - (coughtError.stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError); + (caughtError.stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError); function getFrames(error) { return error.stack ? error.stack.split(NEWLINE) : []; } @@ -77,6 +81,19 @@ function renderLongStackTrace(frames, stack) { Zone['longStackTraceZoneSpec'] = { name: 'long-stack-trace', longStackTraceLimit: 10, + // add a getLongStackTrace method in spec to + // handle handled reject promise error. + getLongStackTrace: function (error) { + if (!error) { + return undefined; + } + var task = error[Zone['__symbol__']('currentTask')]; + var trace = task && task.data && task.data[creationTrace]; + if (!trace) { + return error.stack; + } + return renderLongStackTrace(trace, error.stack); + }, onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) { var currentTask = Zone.currentTask; var trace = currentTask && currentTask.data && currentTask.data[creationTrace] || []; @@ -107,7 +124,7 @@ Zone['longStackTraceZoneSpec'] = { stackSetSucceeded = true; } } - catch (e) { + catch (err) { } var longStack = stackSetSucceeded ? null : @@ -116,14 +133,14 @@ Zone['longStackTraceZoneSpec'] = { try { stackSetSucceeded = error.stack = longStack; } - catch (e) { + catch (err) { } } if (!stackSetSucceeded) { try { stackSetSucceeded = error.longStack = longStack; } - catch (e) { + catch (err) { } } } diff --git a/dist/long-stack-trace-zone.min.js b/dist/long-stack-trace-zone.min.js index db33700a3..59cf38dbe 100644 --- a/dist/long-stack-trace-zone.min.js +++ b/dist/long-stack-trace-zone.min.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e():"function"==typeof define&&define.amd?define(e):e()}(this,function(){"use strict";function t(){return new Error("STACKTRACE TRACKING")}function e(){try{throw t()}catch(e){return e}}function n(t){return t.stack?t.stack.split(i):[]}function r(t,e){for(var r=n(e),a=0;a0&&(t.push(n((new l).error)),c(t,e-1))}function o(){var t=[];c(t,2);for(var e=t[0],n=t[1],r=0;rthis.longStackTraceLimit&&(c.length=this.longStackTraceLimit),r.data||(r.data={}),r.data[f]=c,t.scheduleTask(n,r)},onHandleError:function(t,e,n,r){var c=Zone.currentTask||r.task;if(r instanceof Error&&c){var o=null;try{var i=Object.getOwnPropertyDescriptor(r,"stack");if(i&&i.configurable){var u=i.get,s=i.value;i={get:function(){return a(c.data&&c.data[f],u?u.apply(this):s)}},Object.defineProperty(r,"stack",i),o=!0}}catch(l){}var h=o?null:a(c.data&&c.data[f],r.stack);if(!o)try{o=r.stack=h}catch(l){}if(!o)try{o=r.longStack=h}catch(l){}}return t.handleError(n,r)}},o()}); \ No newline at end of file +!function(t,a){"object"==typeof exports&&"undefined"!=typeof module?a():"function"==typeof define&&define.amd?define(a):a()}(this,function(){"use strict";function t(){return new Error("STACKTRACE TRACKING")}function a(){try{throw t()}catch(a){return a}}function e(t){return t.stack?t.stack.split(i):[]}function n(t,a){for(var n=e(a),r=0;r0&&(t.push(e((new l).error)),c(t,a-1))}function o(){var t=[];c(t,2);for(var a=t[0],e=t[1],n=0;nthis.longStackTraceLimit&&(c.length=this.longStackTraceLimit),n.data||(n.data={}),n.data[f]=c,t.scheduleTask(e,n)},onHandleError:function(t,a,e,n){var c=Zone.currentTask||n.task;if(n instanceof Error&&c){var o=null;try{var i=Object.getOwnPropertyDescriptor(n,"stack");if(i&&i.configurable){var u=i.get,s=i.value;i={get:function(){return r(c.data&&c.data[f],u?u.apply(this):s)}},Object.defineProperty(n,"stack",i),o=!0}}catch(l){}var d=o?null:r(c.data&&c.data[f],n.stack);if(!o)try{o=n.stack=d}catch(l){}if(!o)try{o=n.longStack=d}catch(l){}}return t.handleError(e,n)}},o()}); \ No newline at end of file diff --git a/dist/mocha-patch.js b/dist/mocha-patch.js index e3da97cdb..094718899 100644 --- a/dist/mocha-patch.js +++ b/dist/mocha-patch.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -48,7 +48,7 @@ it: Mocha.it }; function modifyArguments(args, syncTest, asyncTest) { - var _loop_1 = function (i) { + var _loop_1 = function(i) { var arg = args[i]; if (typeof arg === 'function') { // The `done` callback is only passed through if the function expects at diff --git a/dist/proxy.js b/dist/proxy.js index c09fbd8ae..506dbd2df 100644 --- a/dist/proxy.js +++ b/dist/proxy.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** diff --git a/dist/sync-test.js b/dist/sync-test.js index 197f13d63..395b8834d 100644 --- a/dist/sync-test.js +++ b/dist/sync-test.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** diff --git a/dist/task-tracking.js b/dist/task-tracking.js index 40fc31f41..f244854ed 100644 --- a/dist/task-tracking.js +++ b/dist/task-tracking.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** diff --git a/dist/webapis-media-query.js b/dist/webapis-media-query.js index 9ed5abe23..69e0f9f3e 100644 --- a/dist/webapis-media-query.js +++ b/dist/webapis-media-query.js @@ -1 +1,57 @@ -!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(this,function(){"use strict";function e(e,n,t,r,i){var u=e[c];if(u)for(var o=0;o 0, change: type }; - try { - this.hasTask(this.zone, isEmpty); - } - finally { - if (this._parentDelegate) { - this._parentDelegate._updateTaskCount(type, count); - } - } + // TODO(misko): what should happen if it throws? + this.hasTask(this.zone, isEmpty); } }; return ZoneDelegate; }()); var ZoneTask = (function () { - function ZoneTask(type, zone, source, callback, options, scheduleFn, cancelFn) { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this.zone = null; this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; this.type = type; - this.zone = zone; this.source = source; this.data = options; this.scheduleFn = scheduleFn; @@ -342,7 +416,8 @@ var Zone$1 = (function (global) { this.invoke = function () { _numberOfNestedTaskFrames++; try { - return zone.runTask(self, this, arguments); + self.runCount++; + return self.zone.runTask(self, this, arguments); } finally { if (_numberOfNestedTaskFrames == 1) { @@ -352,6 +427,29 @@ var Zone$1 = (function (global) { } }; } + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: true, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(this.type + " '" + this.source + "': can not transition to '" + toState + "', expecting state '" + fromState1 + "'" + (fromState2 ? + ' or \'' + fromState2 + '\'' : + '') + ", was '" + this._state + "'."); + } + }; ZoneTask.prototype.toString = function () { if (this.data && typeof this.data.handleId !== 'undefined') { return this.data.handleId; @@ -365,6 +463,7 @@ var Zone$1 = (function (global) { ZoneTask.prototype.toJSON = function () { return { type: this.type, + state: this.state, source: this.source, data: this.data, zone: this.zone.name, @@ -415,12 +514,26 @@ var Zone$1 = (function (global) { _microTaskQueue.push(task); } function consoleError(e) { + if (Zone[__symbol__('ignoreConsoleErrorUncaughtError')]) { + return; + } var rejection = e && e.rejection; if (rejection) { console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); } console.error(e); } + function handleUnhandledRejection(e) { + consoleError(e); + try { + var handler = Zone[__symbol__('unhandledPromiseRejectionHandler')]; + if (handler && typeof handler === 'function') { + handler.apply(this, [e]); + } + } + catch (err) { + } + } function drainMicroTaskQueue() { if (!_isDrainingMicrotaskQueue) { _isDrainingMicrotaskQueue = true; @@ -432,21 +545,21 @@ var Zone$1 = (function (global) { try { task.zone.runTask(task, null, null); } - catch (e) { - consoleError(e); + catch (error) { + consoleError(error); } } } while (_uncaughtPromiseErrors.length) { - var _loop_1 = function () { + var _loop_1 = function() { var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); try { uncaughtPromiseError.zone.runGuarded(function () { throw uncaughtPromiseError; }); } - catch (e) { - consoleError(e); + catch (error) { + handleUnhandledRejection(error); } }; while (_uncaughtPromiseErrors.length) { @@ -474,24 +587,75 @@ var Zone$1 = (function (global) { var REJECTED_NO_CATCH = 0; function makeResolver(promise, state) { return function (v) { - resolvePromise(promise, state, v); + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } // Do not return value or you will break the Promise spec. }; } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + // Promise Resolution function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError('Promise resolved with itself'); + } if (promise[symbolState] === UNRESOLVED) { - if (value instanceof ZoneAwarePromise && value.hasOwnProperty(symbolState) && - value.hasOwnProperty(symbolValue) && value[symbolState] !== UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { clearRejectedNoCatch(value); resolvePromise(promise, value[symbolState], value[symbolValue]); } - else if (isThenable(value)) { - value.then(makeResolver(promise, state), makeResolver(promise, false)); + else if (state !== REJECTED && typeof then === 'function') { + try { + then.apply(value, [ + onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false)) + ]); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } } else { promise[symbolState] = state; var queue = promise[symbolValue]; promise[symbolValue] = value; + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + value[__symbol__('currentTask')] = Zone.currentTask; + } for (var i = 0; i < queue.length;) { scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); } @@ -501,8 +665,8 @@ var Zone$1 = (function (global) { throw new Error('Uncaught (in promise): ' + value + (value && value.stack ? '\n' + value.stack : '')); } - catch (e) { - var error_1 = e; + catch (err) { + var error_1 = err; error_1.rejection = value; error_1.promise = promise; error_1.zone = Zone.current; @@ -518,21 +682,35 @@ var Zone$1 = (function (global) { } function clearRejectedNoCatch(promise) { if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[__symbol__('rejectionHandledHandler')]; + if (handler && typeof handler === 'function') { + handler.apply(this, [{ rejection: promise[symbolValue], promise: promise }]); + } + } + catch (err) { + } promise[symbolState] = REJECTED; for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { if (promise === _uncaughtPromiseErrors[i].promise) { _uncaughtPromiseErrors.splice(i, 1); - break; } } } } function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { clearRejectedNoCatch(promise); - var delegate = promise[symbolState] ? onFulfilled || forwardResolution : onRejected || forwardRejection; + var delegate = promise[symbolState] ? + (typeof onFulfilled === 'function') ? onFulfilled : forwardResolution : + (typeof onRejected === 'function') ? onRejected : forwardRejection; zone.scheduleMicroTask(source, function () { try { - resolvePromise(chainPromise, true, zone.run(delegate, null, [promise[symbolValue]])); + resolvePromise(chainPromise, true, zone.run(delegate, undefined, [promise[symbolValue]])); } catch (error) { resolvePromise(chainPromise, false, error); @@ -550,8 +728,8 @@ var Zone$1 = (function (global) { try { executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED)); } - catch (e) { - resolvePromise(promise, false, e); + catch (error) { + resolvePromise(promise, false, error); } } ZoneAwarePromise.toString = function () { @@ -634,38 +812,41 @@ var Zone$1 = (function (global) { ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; ZoneAwarePromise['race'] = ZoneAwarePromise.race; ZoneAwarePromise['all'] = ZoneAwarePromise.all; - var NativePromise = global[__symbol__('Promise')] = global['Promise']; + var NativePromise = global[symbolPromise] = global['Promise']; global['Promise'] = ZoneAwarePromise; - function patchThen(NativePromise) { - var NativePromiseProtototype = NativePromise.prototype; - var NativePromiseThen = NativePromiseProtototype[__symbol__('then')] = - NativePromiseProtototype.then; - NativePromiseProtototype.then = function (onResolve, onReject) { - var nativePromise = this; - return new ZoneAwarePromise(function (resolve, reject) { - NativePromiseThen.call(nativePromise, resolve, reject); - }) - .then(onResolve, onReject); + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); }; + Ctor[symbolThenPatched] = true; } - if (NativePromise) { - patchThen(NativePromise); - if (typeof global['fetch'] !== 'undefined') { - var fetchPromise = void 0; - try { - // In MS Edge this throws - fetchPromise = global['fetch'](); - } - catch (e) { - // In Chrome this throws instead. - fetchPromise = global['fetch']('about:blank'); + function zoneify(fn) { + return function () { + var resultPromise = fn.apply(this, arguments); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; } - // ignore output to prevent error; - fetchPromise.then(function () { return null; }, function () { return null; }); - if (fetchPromise.constructor != NativePromise && - fetchPromise.constructor != ZoneAwarePromise) { - patchThen(fetchPromise.constructor); + var Ctor = resultPromise.constructor; + if (!Ctor[symbolThenPatched]) { + patchThen(Ctor); } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + var fetch = global['fetch']; + if (typeof fetch == 'function') { + global['fetch'] = zoneify(fetch); } } // This is not part of public API, but it is usefull for tests, so we expose it. @@ -691,36 +872,109 @@ var Zone$1 = (function (global) { // How should the stack frames be parsed. var frameParserStrategy = null; var stackRewrite = 'stackRewrite'; - var assignAll = function (to, from) { - if (!to) { - return to; - } - if (from) { - var keys = Object.getOwnPropertyNames(from); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(from, key)) { - to[key] = from[key]; + // fix #595, create property descriptor + // for error properties + var createProperty = function (props, key) { + // if property is already defined, skip it. + if (props[key]) { + return; + } + // define a local property + // in case error property is not settable + var name = __symbol__(key); + props[key] = { + configurable: true, + enumerable: true, + get: function () { + // if local property has no value + // use internal error's property value + if (!this[name]) { + var error_2 = this[__symbol__('error')]; + if (error_2) { + this[name] = error_2[key]; + } } + return this[name]; + }, + set: function (value) { + // setter will set value to local property value + this[name] = value; } - // copy all properties from prototype - // in Error, property such as name/message is in Error's prototype - // but not enumerable, so we copy those properties through - // Error's prototype - var proto = Object.getPrototypeOf(from); - if (proto) { - var pKeys = Object.getOwnPropertyNames(proto); - for (var i = 0; i < pKeys.length; i++) { - var key = pKeys[i]; - // skip constructor - if (key !== 'constructor') { - to[key] = from[key]; - } + }; + }; + // fix #595, create property descriptor + // for error method properties + var createMethodProperty = function (props, key) { + if (props[key]) { + return; + } + props[key] = { + configurable: true, + enumerable: true, + writable: true, + value: function () { + var error = this[__symbol__('error')]; + var errorMethod = (error && error[key]) || this[key]; + if (errorMethod) { + return errorMethod.apply(error, arguments); + } + } + }; + }; + var createErrorProperties = function () { + var props = Object.create(null); + var error = new NativeError(); + var keys = Object.getOwnPropertyNames(error); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(error, key)) { + createProperty(props, key); + } + } + var proto = NativeError.prototype; + if (proto) { + var pKeys = Object.getOwnPropertyNames(proto); + for (var i = 0; i < pKeys.length; i++) { + var key = pKeys[i]; + // skip constructor + if (key !== 'constructor' && key !== 'toString' && key !== 'toSource') { + createProperty(props, key); } } } - return to; + // some other properties are not + // in NativeError + createProperty(props, 'originalStack'); + createProperty(props, 'zoneAwareStack'); + // define toString, toSource as method property + createMethodProperty(props, 'toString'); + createMethodProperty(props, 'toSource'); + return props; + }; + var errorProperties = createErrorProperties(); + // for derived Error class which extends ZoneAwareError + // we should not override the derived class's property + // so we create a new props object only copy the properties + // from errorProperties which not exist in derived Error's prototype + var getErrorPropertiesForPrototype = function (prototype) { + // if the prototype is ZoneAwareError.prototype + // we just return the prebuilt errorProperties. + if (prototype === ZoneAwareError.prototype) { + return errorProperties; + } + var newProps = Object.create(null); + var cKeys = Object.getOwnPropertyNames(errorProperties); + var keys = Object.getOwnPropertyNames(prototype); + cKeys.forEach(function (cKey) { + if (keys.filter(function (key) { + return key === cKey; + }) + .length === 0) { + newProps[cKey] = errorProperties[cKey]; + } + }); + return newProps; }; /** * This is ZoneAwareError which processes the stack frame and cleans up extra frames as well as @@ -736,6 +990,7 @@ var Zone$1 = (function (global) { } // Create an Error. var error = NativeError.apply(this, arguments); + this[__symbol__('error')] = error; // Save original stack trace error.originalStack = error.stack; // Process the stack trace and rewrite the frames. @@ -772,12 +1027,33 @@ var Zone$1 = (function (global) { } error.stack = error.zoneAwareStack = frames_1.join('\n'); } - return assignAll(this, error); + // use defineProperties here instead of copy property value + // because of issue #595 which will break angular2. + Object.defineProperties(this, getErrorPropertiesForPrototype(Object.getPrototypeOf(this))); + return this; } // Copy the prototype so that instanceof operator works as expected ZoneAwareError.prototype = NativeError.prototype; ZoneAwareError[Zone.__symbol__('blacklistedStackFrames')] = blackListedStackFrames; ZoneAwareError[stackRewrite] = false; + // those properties need special handling + var specialPropertyNames = ['stackTraceLimit', 'captureStackTrace', 'prepareStackTrace']; + // those properties of NativeError should be set to ZoneAwareError + var nativeErrorProperties = Object.keys(NativeError); + if (nativeErrorProperties) { + nativeErrorProperties.forEach(function (prop) { + if (specialPropertyNames.filter(function (sp) { return sp === prop; }).length === 0) { + Object.defineProperty(ZoneAwareError, prop, { + get: function () { + return NativeError[prop]; + }, + set: function (value) { + NativeError[prop] = value; + } + }); + } + }); + } if (NativeError.hasOwnProperty('stackTraceLimit')) { // Extend default stack limit as we will be removing few frames. NativeError.stackTraceLimit = Math.max(NativeError.stackTraceLimit, 15); @@ -813,7 +1089,7 @@ var Zone$1 = (function (global) { if (structuredStackTrace) { for (var i = 0; i < structuredStackTrace.length; i++) { var st = structuredStackTrace[i]; - // remove the first function which name is value + // remove the first function which name is zoneCaptureStackTrace if (st.getFunctionName() === 'zoneCaptureStackTrace') { structuredStackTrace.splice(i, 1); break; @@ -903,9 +1179,9 @@ var Zone$1 = (function (global) { /** * Suppress closure compiler errors about unknown 'Zone' variable * @fileoverview - * @suppress {undefinedVars} + * @suppress {undefinedVars,globalThis} */ -var zoneSymbol = function (n) { return "__zone_symbol__" + n; }; +var zoneSymbol = function (n) { return ("__zone_symbol__" + n); }; var _global$1 = typeof window === 'object' && window || typeof self === 'object' && self || global; function bindArguments(args, source) { for (var i = args.length - 1; i >= 0; i--) { @@ -917,7 +1193,7 @@ function bindArguments(args, source) { } function patchPrototype(prototype, fnNames) { var source = prototype.constructor['name']; - var _loop_1 = function (i) { + var _loop_1 = function(i) { var name_1 = fnNames[i]; var delegate = prototype[name_1]; if (delegate) { @@ -938,8 +1214,8 @@ var isNode = (!('nw' in _global$1) && typeof process !== 'undefined' && var isBrowser = !isNode && !isWebWorker && !!(typeof window !== 'undefined' && window['HTMLElement']); // we are in electron of nw, so we are both browser and nodejs var isMix = typeof process !== 'undefined' && - {}.toString.call(process) === '[object process]' && - !isWebWorker && !!(typeof window !== 'undefined' && window['HTMLElement']); + {}.toString.call(process) === '[object process]' && !isWebWorker && + !!(typeof window !== 'undefined' && window['HTMLElement']); function patchProperty(obj, prop) { var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; var originalDesc = Object.getOwnPropertyDescriptor(obj, 'original' + prop); @@ -955,7 +1231,7 @@ function patchProperty(obj, prop) { delete desc.value; // substr(2) cuz 'onclick' -> 'click', etc var eventName = prop.substr(2); - var _prop = '_' + prop; + var _prop = zoneSymbol('_' + prop); desc.set = function (fn) { if (this[_prop]) { this.removeEventListener(eventName, this[_prop]); @@ -983,14 +1259,15 @@ function patchProperty(obj, prop) { // because the onclick function is internal raw uncompiled handler // the onclick will be evaluated when first time event was triggered or // the property is accessed, https://github.com/angular/zone.js/issues/525 - // so we should use original native get to retrive the handler + // so we should use original native get to retrieve the handler if (r === null) { - var oriDesc = Object.getOwnPropertyDescriptor(obj, 'original' + prop); - if (oriDesc && oriDesc.get) { - r = oriDesc.get.apply(this, arguments); + if (originalDesc && originalDesc.get) { + r = originalDesc.get.apply(this, arguments); if (r) { desc.set.apply(this, [r]); - this.removeAttribute(prop); + if (typeof this['removeAttribute'] === 'function') { + this.removeAttribute(prop); + } } } } @@ -1131,7 +1408,7 @@ function makeZoneAwareAddListener(addFnName, removeFnName, useCapturingParam, al // will fail tests prematurely. validZoneHandler = data.handler && data.handler.toString() === '[object FunctionWrapper]'; } - catch (e) { + catch (error) { // Returning nothing here is fine, because objects in a cross-site context are unusable return; } @@ -1293,7 +1570,7 @@ function createNamedFn(name, delegate) { try { return (Function('f', "return function " + name + "(){return f(this, arguments)}"))(delegate); } - catch (e) { + catch (error) { // if we fail, we must be CSP, just return delegate. return function () { return delegate(this, arguments); @@ -1317,7 +1594,7 @@ function patchMethod(target, name, patchFn) { } return delegate; } -// TODO: support cancel task later if necessary +// TODO: @JiaLiPassion, support cancel task later if necessary function patchMacroTask(obj, funcName, metaCreator) { var setNative = null; function scheduleTask(task) { @@ -1340,6 +1617,45 @@ function patchMacroTask(obj, funcName, metaCreator) { } }; }); } +function patchMicroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.callbackIndex] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.callbackIndex >= 0 && typeof args[meta.callbackIndex] === 'function') { + var task = Zone.current.scheduleMicroTask(meta.name, args[meta.callbackIndex], meta, scheduleTask); + return task; + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); +} +function findEventTask(target, evtName) { + var eventTasks = target[zoneSymbol('eventTasks')]; + var result = []; + if (eventTasks) { + for (var i = 0; i < eventTasks.length; i++) { + var eventTask = eventTasks[i]; + var data = eventTask.data; + var eventName = data && data.eventName; + if (eventName === evtName) { + result.push(eventTask); + } + } + } + return result; +} +Zone[zoneSymbol('patchEventTargetMethods')] = patchEventTargetMethods; +Zone[zoneSymbol('patchOnProperties')] = patchOnProperties; /** * @license @@ -1357,8 +1673,12 @@ function patchTimer(window, setName, cancelName, nameSuffix) { function scheduleTask(task) { var data = task.data; data.args[0] = function () { - task.invoke.apply(this, arguments); - delete tasksByHandleId[data.handleId]; + try { + task.invoke.apply(this, arguments); + } + finally { + delete tasksByHandleId[data.handleId]; + } }; data.handleId = setNative.apply(window, data.args); tasksByHandleId[data.handleId] = task; @@ -1384,7 +1704,10 @@ function patchTimer(window, setName, cancelName, nameSuffix) { } // Node.js must additionally support the ref and unref functions. var handle = task.data.handleId; - if (handle.ref && handle.unref) { + // check whether handle is null, because some polyfill or browser + // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame + if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' && + typeof handle.unref === 'function') { task.ref = handle.ref.bind(handle); task.unref = handle.unref.bind(handle); } @@ -1399,7 +1722,8 @@ function patchTimer(window, setName, cancelName, nameSuffix) { patchMethod(window, cancelName, function (delegate) { return function (self, args) { var task = typeof args[0] === 'number' ? tasksByHandleId[args[0]] : args[0]; if (task && typeof task.type === 'string') { - if (task.cancelFn && task.data.isPeriodic || task.runCount === 0) { + if (task.state !== 'notScheduled' && + (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) { // Do not cancel already canceled functions task.zone.cancelTask(task); } @@ -1484,7 +1808,7 @@ function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { try { return _defineProperty(obj, prop, desc); } - catch (e) { + catch (error) { if (desc.configurable) { // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's // retry with the original flag value @@ -1497,19 +1821,19 @@ function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { try { return _defineProperty(obj, prop, desc); } - catch (e) { + catch (error) { var descJson = null; try { descJson = JSON.stringify(desc); } - catch (e) { + catch (error) { descJson = descJson.toString(); } - console.log("Attempting to configure '" + prop + "' with descriptor '" + descJson + "' on object '" + obj + "' and got error, giving up: " + e); + console.log("Attempting to configure '" + prop + "' with descriptor '" + descJson + "' on object '" + obj + "' and got error, giving up: " + error); } } else { - throw e; + throw error; } } } @@ -1636,6 +1960,7 @@ function canPatchViaPropertyDescriptor() { if (desc && !desc.configurable) return false; } + var xhrDesc = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'onreadystatechange'); // add enumerable and configurable here because in opera // by default XMLHttpRequest.prototype.onreadystatechange is undefined // without adding enumerable and configurable will cause onreadystatechange @@ -1649,7 +1974,8 @@ function canPatchViaPropertyDescriptor() { }); var req = new XMLHttpRequest(); var result = !!req.onreadystatechange; - Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', {}); + // restore original desc + Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {}); return result; } @@ -1658,7 +1984,7 @@ var unboundKey = zoneSymbol('unbound'); // for `onwhatever` properties and replace them with zone-bound functions // - Chrome (for now) function patchViaCapturingAllTheEvents() { - var _loop_1 = function (i) { + var _loop_1 = function(i) { var property = eventNames[i]; var onproperty = 'on' + property; self.addEventListener(property, function (event) { @@ -1774,7 +2100,9 @@ function patchXHR(window) { } var newListener = data.target[XHR_LISTENER] = function () { if (data.target.readyState === data.target.DONE) { - if (!data.aborted && self[XHR_SCHEDULED]) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && self[XHR_SCHEDULED] && task.state === 'scheduled') { task.invoke(); } } @@ -1831,6 +2159,26 @@ function patchXHR(window) { if (_global['navigator'] && _global['navigator'].geolocation) { patchPrototype(_global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); } +// handle unhandled promise rejection +function findPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTask(_global, evtName); + eventTasks.forEach(function (eventTask) { + // windows has added unhandledrejection event listener + // trigger the event listener + var PromiseRejectionEvent = _global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + var evt = new PromiseRejectionEvent(evtName, { promise: e.promise, reason: e.rejection }); + eventTask.invoke(evt); + } + }); + }; +} +if (_global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = findPromiseRejectionHandler('rejectionhandled'); +} /** * @license @@ -1852,16 +2200,16 @@ var EE_REMOVE_LISTENER = 'removeListener'; var EE_REMOVE_ALL_LISTENER = 'removeAllListeners'; var EE_LISTENERS = 'listeners'; var EE_ON = 'on'; -var zoneAwareAddListener$1 = callAndReturnFirstParam(makeZoneAwareAddListener(EE_ADD_LISTENER, EE_REMOVE_LISTENER, false, true, false)); +var zoneAwareAddListener = callAndReturnFirstParam(makeZoneAwareAddListener(EE_ADD_LISTENER, EE_REMOVE_LISTENER, false, true, false)); var zoneAwarePrependListener = callAndReturnFirstParam(makeZoneAwareAddListener(EE_PREPEND_LISTENER, EE_REMOVE_LISTENER, false, true, true)); -var zoneAwareRemoveListener$1 = callAndReturnFirstParam(makeZoneAwareRemoveListener(EE_REMOVE_LISTENER, false)); +var zoneAwareRemoveListener = callAndReturnFirstParam(makeZoneAwareRemoveListener(EE_REMOVE_LISTENER, false)); var zoneAwareRemoveAllListeners = callAndReturnFirstParam(makeZoneAwareRemoveAllListeners(EE_REMOVE_ALL_LISTENER, false)); var zoneAwareListeners = makeZoneAwareListeners(EE_LISTENERS); function patchEventEmitterMethods(obj) { if (obj && obj.addListener) { - patchMethod(obj, EE_ADD_LISTENER, function () { return zoneAwareAddListener$1; }); + patchMethod(obj, EE_ADD_LISTENER, function () { return zoneAwareAddListener; }); patchMethod(obj, EE_PREPEND_LISTENER, function () { return zoneAwarePrependListener; }); - patchMethod(obj, EE_REMOVE_LISTENER, function () { return zoneAwareRemoveListener$1; }); + patchMethod(obj, EE_REMOVE_LISTENER, function () { return zoneAwareRemoveListener; }); patchMethod(obj, EE_REMOVE_ALL_LISTENER, function () { return zoneAwareRemoveAllListeners; }); patchMethod(obj, EE_LISTENERS, function () { return zoneAwareListeners; }); obj[EE_ON] = obj[EE_ADD_LISTENER]; @@ -1939,7 +2287,9 @@ if (shouldPatchGlobalTimers) { patchTimer(_global$2, set$1, clear$1, 'Interval'); patchTimer(_global$2, set$1, clear$1, 'Immediate'); } -patchNextTick(); +// patch process related methods +patchProcess(); +handleUnhandledPromiseRejection(); // Crypto var crypto; try { @@ -1947,78 +2297,52 @@ try { } catch (err) { } -// TODO(gdi2290): implement a better way to patch these methods +// use the generic patchMacroTask to patch crypto if (crypto) { - var nativeRandomBytes_1 = crypto.randomBytes; - crypto.randomBytes = function randomBytesZone(size, callback) { - if (!callback) { - return nativeRandomBytes_1(size); - } - else { - var zone = Zone.current; - var source = crypto.constructor.name + '.randomBytes'; - return nativeRandomBytes_1(size, zone.wrap(callback, source)); - } - }.bind(crypto); - var nativePbkdf2_1 = crypto.pbkdf2; - crypto.pbkdf2 = function pbkdf2Zone() { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - var fn = args[args.length - 1]; - if (typeof fn === 'function') { - var zone = Zone.current; - var source = crypto.constructor.name + '.pbkdf2'; - args[args.length - 1] = zone.wrap(fn, source); - return nativePbkdf2_1.apply(void 0, args); - } - else { - return nativePbkdf2_1.apply(void 0, args); - } - }.bind(crypto); -} -// HTTP Client -var httpClient; -try { - httpClient = require('_http_client'); + var methodNames = ['randomBytes', 'pbkdf2']; + methodNames.forEach(function (name) { + patchMacroTask(crypto, name, function (self, args) { + return { + name: 'crypto.' + name, + args: args, + callbackIndex: (args.length > 0 && typeof args[args.length - 1] === 'function') ? args.length - 1 : -1, + target: crypto + }; + }); + }); } -catch (err) { +function patchProcess() { + // patch nextTick as microTask + patchMicroTask(process, 'nextTick', function (self, args) { + return { + name: 'process.nextTick', + args: args, + callbackIndex: (args.length > 0 && typeof args[0] === 'function') ? 0 : -1, + target: process + }; + }); } -if (httpClient && httpClient.ClientRequest) { - var ClientRequest_1 = httpClient.ClientRequest.bind(httpClient); - httpClient.ClientRequest = function (options, callback) { - if (!callback) { - return new ClientRequest_1(options); - } - else { - var zone = Zone.current; - return new ClientRequest_1(options, zone.wrap(callback, 'http.ClientRequest')); - } +// handle unhandled promise rejection +function findProcessPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTask(process, evtName); + eventTasks.forEach(function (eventTask) { + // process has added unhandledrejection event listener + // trigger the event listener + if (evtName === 'unhandledRejection') { + eventTask.invoke(e.rejection, e.promise); + } + else if (evtName === 'rejectionHandled') { + eventTask.invoke(e.promise); + } + }); }; } -function patchNextTick() { - var setNative = null; - function scheduleTask(task) { - var args = task.data; - args[0] = function () { - task.invoke.apply(this, arguments); - }; - setNative.apply(process, args); - return task; - } - setNative = - patchMethod(process, 'nextTick', function (delegate) { return function (self, args) { - if (typeof args[0] === 'function') { - var zone = Zone.current; - var task = zone.scheduleMicroTask('nextTick', args[0], args, scheduleTask); - return task; - } - else { - // cause an error by calling it directly. - return delegate.apply(process, args); - } - }; }); +function handleUnhandledPromiseRejection() { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findProcessPromiseRejectionHandler('unhandledRejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findProcessPromiseRejectionHandler('rejectionHandled'); } /** diff --git a/dist/zone-node.js b/dist/zone-node.js index ada6f0adb..1cf73a5f3 100644 --- a/dist/zone-node.js +++ b/dist/zone-node.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -19,11 +19,13 @@ * found in the LICENSE file at https://angular.io/license */ - var Zone$1 = (function (global) { if (global['Zone']) { throw new Error('Zone already loaded.'); } + var NO_ZONE = { name: 'NO ZONE' }; + var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling'; + var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; var Zone = (function () { function Zone(parent, zoneSpec) { this._properties = null; @@ -42,6 +44,17 @@ var Zone$1 = (function (global) { 'If you must load one, do so before loading zone.js.)'); } }; + Object.defineProperty(Zone, "root", { + get: function () { + var zone = Zone.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + }, + enumerable: true, + configurable: true + }); Object.defineProperty(Zone, "current", { get: function () { return _currentZoneFrame.zone; @@ -105,7 +118,7 @@ var Zone$1 = (function (global) { }; }; Zone.prototype.run = function (callback, applyThis, applyArgs, source) { - if (applyThis === void 0) { applyThis = null; } + if (applyThis === void 0) { applyThis = undefined; } if (applyArgs === void 0) { applyArgs = null; } if (source === void 0) { source = null; } _currentZoneFrame = new ZoneFrame(_currentZoneFrame, this); @@ -136,15 +149,17 @@ var Zone$1 = (function (global) { } }; Zone.prototype.runTask = function (task, applyThis, applyArgs) { - task.runCount++; if (task.zone != this) - throw new Error('A task can only be run in the zone which created it! (Creation: ' + task.zone.name + - '; Execution: ' + this.name + ')'); + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')'); + var reEntryGuard = task.state != running; + reEntryGuard && task._transitionTo(running, scheduled); + task.runCount++; var previousTask = _currentTask; _currentTask = task; _currentZoneFrame = new ZoneFrame(_currentZoneFrame, this); try { - if (task.type == 'macroTask' && task.data && !task.data.isPeriodic) { + if (task.type == macroTask && task.data && !task.data.isPeriodic) { task.cancelFn = null; } try { @@ -157,29 +172,81 @@ var Zone$1 = (function (global) { } } finally { + if (task.type == eventTask || (task.data && task.data.isPeriodic)) { + // if the task's state is notScheduled, then it has already been cancelled + // we should not reset the state to scheduled + if (task.state !== notScheduled) { + reEntryGuard && task._transitionTo(scheduled, running); + } + } + else { + task.runCount = 0; + this._updateTaskCount(task, -1); + reEntryGuard && task._transitionTo(notScheduled, running, notScheduled); + } _currentZoneFrame = _currentZoneFrame.parent; _currentTask = previousTask; } }; + Zone.prototype.scheduleTask = function (task) { + task._transitionTo(scheduling, notScheduled); + var zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task.zone = this; + task = this._zoneDelegate.scheduleTask(this, task); + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + }; Zone.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { - return this._zoneDelegate.scheduleTask(this, new ZoneTask('microTask', this, source, callback, data, customSchedule, null)); + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, null)); }; Zone.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { - return this._zoneDelegate.scheduleTask(this, new ZoneTask('macroTask', this, source, callback, data, customSchedule, customCancel)); + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); }; Zone.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { - return this._zoneDelegate.scheduleTask(this, new ZoneTask('eventTask', this, source, callback, data, customSchedule, customCancel)); + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); }; Zone.prototype.cancelTask = function (task) { - var value = this._zoneDelegate.cancelTask(this, task); - task.runCount = -1; - task.cancelFn = null; - return value; + task._transitionTo(canceling, scheduled, running); + this._zoneDelegate.cancelTask(this, task); + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = 0; + return task; }; + Zone.prototype._updateTaskCount = function (task, count) { + var zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (var i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + }; + Zone.__symbol__ = __symbol__; return Zone; }()); - Zone.__symbol__ = __symbol__; - + var DELEGATE_ZS = { + name: '', + onHasTask: function (delegate, _, target, hasTaskState) { + return delegate.hasTask(target, hasTaskState); + }, + onScheduleTask: function (delegate, _, target, task) { + return delegate.scheduleTask(target, task); + }, + onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { + return delegate.invokeTask(target, task, applyThis, applyArgs); + }, + onCancelTask: function (delegate, _, target, task) { + return delegate.cancelTask(target, task); + } + }; var ZoneDelegate = (function () { function ZoneDelegate(zone, parentDelegate, zoneSpec) { this._taskCounts = { microTask: 0, macroTask: 0, eventTask: 0 }; @@ -222,10 +289,35 @@ var Zone$1 = (function (global) { zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); this._cancelTaskCurrZone = zoneSpec && (zoneSpec.onCancelTask ? this.zone : parentDelegate.zone); - this._hasTaskZS = zoneSpec && (zoneSpec.onHasTask ? zoneSpec : parentDelegate._hasTaskZS); - this._hasTaskDlgt = - zoneSpec && (zoneSpec.onHasTask ? parentDelegate : parentDelegate._hasTaskDlgt); - this._hasTaskCurrZone = zoneSpec && (zoneSpec.onHasTask ? this.zone : parentDelegate.zone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + var parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this.zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this.zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this.zone; + } + } } ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { return this._forkZS ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) : @@ -247,55 +339,41 @@ var Zone$1 = (function (global) { true; }; ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { - try { - if (this._scheduleTaskZS) { - return this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + var returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); } - else if (task.scheduleFn) { + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { task.scheduleFn(task); } - else if (task.type == 'microTask') { + else if (task.type == microTask) { scheduleMicroTask(task); } else { throw new Error('Task is missing scheduleFn.'); } - return task; - } - finally { - if (targetZone == this.zone) { - this._updateTaskCount(task.type, 1); - } } + return returnTask; }; ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { - try { - return this._invokeTaskZS ? - this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : - task.callback.apply(applyThis, applyArgs); - } - finally { - if (targetZone == this.zone && (task.type != 'eventTask') && - !(task.data && task.data.isPeriodic)) { - this._updateTaskCount(task.type, -1); - } - } + return this._invokeTaskZS ? + this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : + task.callback.apply(applyThis, applyArgs); }; ZoneDelegate.prototype.cancelTask = function (targetZone, task) { var value; if (this._cancelTaskZS) { value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); } - else if (!task.cancelFn) { - throw new Error('Task does not support cancellation, or is already canceled.'); - } else { value = task.cancelFn(task); } - if (targetZone == this.zone) { - // this should not be in the finally block, because exceptions assume not canceled. - this._updateTaskCount(task.type, -1); - } return value; }; ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { @@ -316,23 +394,19 @@ var Zone$1 = (function (global) { eventTask: counts.eventTask > 0, change: type }; - try { - this.hasTask(this.zone, isEmpty); - } - finally { - if (this._parentDelegate) { - this._parentDelegate._updateTaskCount(type, count); - } - } + // TODO(misko): what should happen if it throws? + this.hasTask(this.zone, isEmpty); } }; return ZoneDelegate; }()); var ZoneTask = (function () { - function ZoneTask(type, zone, source, callback, options, scheduleFn, cancelFn) { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this.zone = null; this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; this.type = type; - this.zone = zone; this.source = source; this.data = options; this.scheduleFn = scheduleFn; @@ -342,7 +416,8 @@ var Zone$1 = (function (global) { this.invoke = function () { _numberOfNestedTaskFrames++; try { - return zone.runTask(self, this, arguments); + self.runCount++; + return self.zone.runTask(self, this, arguments); } finally { if (_numberOfNestedTaskFrames == 1) { @@ -352,6 +427,29 @@ var Zone$1 = (function (global) { } }; } + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: true, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(this.type + " '" + this.source + "': can not transition to '" + toState + "', expecting state '" + fromState1 + "'" + (fromState2 ? + ' or \'' + fromState2 + '\'' : + '') + ", was '" + this._state + "'."); + } + }; ZoneTask.prototype.toString = function () { if (this.data && typeof this.data.handleId !== 'undefined') { return this.data.handleId; @@ -365,6 +463,7 @@ var Zone$1 = (function (global) { ZoneTask.prototype.toJSON = function () { return { type: this.type, + state: this.state, source: this.source, data: this.data, zone: this.zone.name, @@ -415,12 +514,26 @@ var Zone$1 = (function (global) { _microTaskQueue.push(task); } function consoleError(e) { + if (Zone[__symbol__('ignoreConsoleErrorUncaughtError')]) { + return; + } var rejection = e && e.rejection; if (rejection) { console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); } console.error(e); } + function handleUnhandledRejection(e) { + consoleError(e); + try { + var handler = Zone[__symbol__('unhandledPromiseRejectionHandler')]; + if (handler && typeof handler === 'function') { + handler.apply(this, [e]); + } + } + catch (err) { + } + } function drainMicroTaskQueue() { if (!_isDrainingMicrotaskQueue) { _isDrainingMicrotaskQueue = true; @@ -432,21 +545,21 @@ var Zone$1 = (function (global) { try { task.zone.runTask(task, null, null); } - catch (e) { - consoleError(e); + catch (error) { + consoleError(error); } } } while (_uncaughtPromiseErrors.length) { - var _loop_1 = function () { + var _loop_1 = function() { var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); try { uncaughtPromiseError.zone.runGuarded(function () { throw uncaughtPromiseError; }); } - catch (e) { - consoleError(e); + catch (error) { + handleUnhandledRejection(error); } }; while (_uncaughtPromiseErrors.length) { @@ -474,24 +587,75 @@ var Zone$1 = (function (global) { var REJECTED_NO_CATCH = 0; function makeResolver(promise, state) { return function (v) { - resolvePromise(promise, state, v); + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } // Do not return value or you will break the Promise spec. }; } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + // Promise Resolution function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError('Promise resolved with itself'); + } if (promise[symbolState] === UNRESOLVED) { - if (value instanceof ZoneAwarePromise && value.hasOwnProperty(symbolState) && - value.hasOwnProperty(symbolValue) && value[symbolState] !== UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { clearRejectedNoCatch(value); resolvePromise(promise, value[symbolState], value[symbolValue]); } - else if (isThenable(value)) { - value.then(makeResolver(promise, state), makeResolver(promise, false)); + else if (state !== REJECTED && typeof then === 'function') { + try { + then.apply(value, [ + onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false)) + ]); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } } else { promise[symbolState] = state; var queue = promise[symbolValue]; promise[symbolValue] = value; + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + value[__symbol__('currentTask')] = Zone.currentTask; + } for (var i = 0; i < queue.length;) { scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); } @@ -501,8 +665,8 @@ var Zone$1 = (function (global) { throw new Error('Uncaught (in promise): ' + value + (value && value.stack ? '\n' + value.stack : '')); } - catch (e) { - var error_1 = e; + catch (err) { + var error_1 = err; error_1.rejection = value; error_1.promise = promise; error_1.zone = Zone.current; @@ -518,21 +682,35 @@ var Zone$1 = (function (global) { } function clearRejectedNoCatch(promise) { if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[__symbol__('rejectionHandledHandler')]; + if (handler && typeof handler === 'function') { + handler.apply(this, [{ rejection: promise[symbolValue], promise: promise }]); + } + } + catch (err) { + } promise[symbolState] = REJECTED; for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { if (promise === _uncaughtPromiseErrors[i].promise) { _uncaughtPromiseErrors.splice(i, 1); - break; } } } } function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { clearRejectedNoCatch(promise); - var delegate = promise[symbolState] ? onFulfilled || forwardResolution : onRejected || forwardRejection; + var delegate = promise[symbolState] ? + (typeof onFulfilled === 'function') ? onFulfilled : forwardResolution : + (typeof onRejected === 'function') ? onRejected : forwardRejection; zone.scheduleMicroTask(source, function () { try { - resolvePromise(chainPromise, true, zone.run(delegate, null, [promise[symbolValue]])); + resolvePromise(chainPromise, true, zone.run(delegate, undefined, [promise[symbolValue]])); } catch (error) { resolvePromise(chainPromise, false, error); @@ -550,8 +728,8 @@ var Zone$1 = (function (global) { try { executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED)); } - catch (e) { - resolvePromise(promise, false, e); + catch (error) { + resolvePromise(promise, false, error); } } ZoneAwarePromise.toString = function () { @@ -634,38 +812,41 @@ var Zone$1 = (function (global) { ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; ZoneAwarePromise['race'] = ZoneAwarePromise.race; ZoneAwarePromise['all'] = ZoneAwarePromise.all; - var NativePromise = global[__symbol__('Promise')] = global['Promise']; + var NativePromise = global[symbolPromise] = global['Promise']; global['Promise'] = ZoneAwarePromise; - function patchThen(NativePromise) { - var NativePromiseProtototype = NativePromise.prototype; - var NativePromiseThen = NativePromiseProtototype[__symbol__('then')] = - NativePromiseProtototype.then; - NativePromiseProtototype.then = function (onResolve, onReject) { - var nativePromise = this; - return new ZoneAwarePromise(function (resolve, reject) { - NativePromiseThen.call(nativePromise, resolve, reject); - }) - .then(onResolve, onReject); + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); }; + Ctor[symbolThenPatched] = true; } - if (NativePromise) { - patchThen(NativePromise); - if (typeof global['fetch'] !== 'undefined') { - var fetchPromise = void 0; - try { - // In MS Edge this throws - fetchPromise = global['fetch'](); - } - catch (e) { - // In Chrome this throws instead. - fetchPromise = global['fetch']('about:blank'); + function zoneify(fn) { + return function () { + var resultPromise = fn.apply(this, arguments); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; } - // ignore output to prevent error; - fetchPromise.then(function () { return null; }, function () { return null; }); - if (fetchPromise.constructor != NativePromise && - fetchPromise.constructor != ZoneAwarePromise) { - patchThen(fetchPromise.constructor); + var Ctor = resultPromise.constructor; + if (!Ctor[symbolThenPatched]) { + patchThen(Ctor); } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + var fetch = global['fetch']; + if (typeof fetch == 'function') { + global['fetch'] = zoneify(fetch); } } // This is not part of public API, but it is usefull for tests, so we expose it. @@ -855,6 +1036,24 @@ var Zone$1 = (function (global) { ZoneAwareError.prototype = NativeError.prototype; ZoneAwareError[Zone.__symbol__('blacklistedStackFrames')] = blackListedStackFrames; ZoneAwareError[stackRewrite] = false; + // those properties need special handling + var specialPropertyNames = ['stackTraceLimit', 'captureStackTrace', 'prepareStackTrace']; + // those properties of NativeError should be set to ZoneAwareError + var nativeErrorProperties = Object.keys(NativeError); + if (nativeErrorProperties) { + nativeErrorProperties.forEach(function (prop) { + if (specialPropertyNames.filter(function (sp) { return sp === prop; }).length === 0) { + Object.defineProperty(ZoneAwareError, prop, { + get: function () { + return NativeError[prop]; + }, + set: function (value) { + NativeError[prop] = value; + } + }); + } + }); + } if (NativeError.hasOwnProperty('stackTraceLimit')) { // Extend default stack limit as we will be removing few frames. NativeError.stackTraceLimit = Math.max(NativeError.stackTraceLimit, 15); @@ -980,26 +1179,96 @@ var Zone$1 = (function (global) { /** * Suppress closure compiler errors about unknown 'Zone' variable * @fileoverview - * @suppress {undefinedVars} + * @suppress {undefinedVars,globalThis} */ -var zoneSymbol = function (n) { return "__zone_symbol__" + n; }; +var zoneSymbol = function (n) { return ("__zone_symbol__" + n); }; var _global$1 = typeof window === 'object' && window || typeof self === 'object' && self || global; -function bindArguments(args, source) { - for (var i = args.length - 1; i >= 0; i--) { - if (typeof args[i] === 'function') { - args[i] = Zone.current.wrap(args[i], source + '_' + i); - } - } - return args; -} +var isWebWorker = (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope); var isNode = (!('nw' in _global$1) && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'); +// we are in electron of nw, so we are both browser and nodejs +var isMix = typeof process !== 'undefined' && + {}.toString.call(process) === '[object process]' && !isWebWorker && + !!(typeof window !== 'undefined' && window['HTMLElement']); +function patchProperty(obj, prop) { + var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; + var originalDesc = Object.getOwnPropertyDescriptor(obj, 'original' + prop); + if (!originalDesc && desc.get) { + Object.defineProperty(obj, 'original' + prop, { enumerable: false, configurable: true, get: desc.get }); + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + // substr(2) cuz 'onclick' -> 'click', etc + var eventName = prop.substr(2); + var _prop = zoneSymbol('_' + prop); + desc.set = function (fn) { + if (this[_prop]) { + this.removeEventListener(eventName, this[_prop]); + } + if (typeof fn === 'function') { + var wrapFn = function (event) { + var result; + result = fn.apply(this, arguments); + if (result != undefined && !result) + event.preventDefault(); + }; + this[_prop] = wrapFn; + this.addEventListener(eventName, wrapFn, false); + } + else { + this[_prop] = null; + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + var r = this[_prop] || null; + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + if (r === null) { + if (originalDesc && originalDesc.get) { + r = originalDesc.get.apply(this, arguments); + if (r) { + desc.set.apply(this, [r]); + if (typeof this['removeAttribute'] === 'function') { + this.removeAttribute(prop); + } + } + } + } + return this[_prop] || null; + }; + Object.defineProperty(obj, prop, desc); +} - - +function patchOnProperties(obj, properties) { + var onProperties = []; + for (var prop in obj) { + if (prop.substr(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (var j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j]); + } + if (properties) { + for (var i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i]); + } + } +} var EVENT_TASKS = zoneSymbol('eventTasks'); // For EventTarget @@ -1116,7 +1385,7 @@ function makeZoneAwareAddListener(addFnName, removeFnName, useCapturingParam, al // will fail tests prematurely. validZoneHandler = data.handler && data.handler.toString() === '[object FunctionWrapper]'; } - catch (e) { + catch (error) { // Returning nothing here is fine, because objects in a cross-site context are unusable return; } @@ -1197,8 +1466,19 @@ function makeZoneAwareListeners(fnName) { } var zoneAwareAddEventListener = makeZoneAwareAddListener(ADD_EVENT_LISTENER, REMOVE_EVENT_LISTENER); var zoneAwareRemoveEventListener = makeZoneAwareRemoveListener(REMOVE_EVENT_LISTENER); - -var originalInstanceKey = zoneSymbol('originalInstance'); +function patchEventTargetMethods(obj, addFnName, removeFnName, metaCreator) { + if (addFnName === void 0) { addFnName = ADD_EVENT_LISTENER; } + if (removeFnName === void 0) { removeFnName = REMOVE_EVENT_LISTENER; } + if (metaCreator === void 0) { metaCreator = defaultListenerMetaCreator; } + if (obj && obj[addFnName]) { + patchMethod(obj, addFnName, function () { return makeZoneAwareAddListener(addFnName, removeFnName, true, false, false, metaCreator); }); + patchMethod(obj, removeFnName, function () { return makeZoneAwareRemoveListener(removeFnName, true, metaCreator); }); + return true; + } + else { + return false; + } +} // wrap some native API on `window` @@ -1206,7 +1486,7 @@ function createNamedFn(name, delegate) { try { return (Function('f', "return function " + name + "(){return f(this, arguments)}"))(delegate); } - catch (e) { + catch (error) { // if we fail, we must be CSP, just return delegate. return function () { return delegate(this, arguments); @@ -1230,7 +1510,7 @@ function patchMethod(target, name, patchFn) { } return delegate; } -// TODO: support cancel task later if necessary +// TODO: @JiaLiPassion, support cancel task later if necessary function patchMacroTask(obj, funcName, metaCreator) { var setNative = null; function scheduleTask(task) { @@ -1253,6 +1533,45 @@ function patchMacroTask(obj, funcName, metaCreator) { } }; }); } +function patchMicroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.callbackIndex] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.callbackIndex >= 0 && typeof args[meta.callbackIndex] === 'function') { + var task = Zone.current.scheduleMicroTask(meta.name, args[meta.callbackIndex], meta, scheduleTask); + return task; + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); +} +function findEventTask(target, evtName) { + var eventTasks = target[zoneSymbol('eventTasks')]; + var result = []; + if (eventTasks) { + for (var i = 0; i < eventTasks.length; i++) { + var eventTask = eventTasks[i]; + var data = eventTask.data; + var eventName = data && data.eventName; + if (eventName === evtName) { + result.push(eventTask); + } + } + } + return result; +} +Zone[zoneSymbol('patchEventTargetMethods')] = patchEventTargetMethods; +Zone[zoneSymbol('patchOnProperties')] = patchOnProperties; /** * @license @@ -1274,16 +1593,16 @@ var EE_REMOVE_LISTENER = 'removeListener'; var EE_REMOVE_ALL_LISTENER = 'removeAllListeners'; var EE_LISTENERS = 'listeners'; var EE_ON = 'on'; -var zoneAwareAddListener$1 = callAndReturnFirstParam(makeZoneAwareAddListener(EE_ADD_LISTENER, EE_REMOVE_LISTENER, false, true, false)); +var zoneAwareAddListener = callAndReturnFirstParam(makeZoneAwareAddListener(EE_ADD_LISTENER, EE_REMOVE_LISTENER, false, true, false)); var zoneAwarePrependListener = callAndReturnFirstParam(makeZoneAwareAddListener(EE_PREPEND_LISTENER, EE_REMOVE_LISTENER, false, true, true)); -var zoneAwareRemoveListener$1 = callAndReturnFirstParam(makeZoneAwareRemoveListener(EE_REMOVE_LISTENER, false)); +var zoneAwareRemoveListener = callAndReturnFirstParam(makeZoneAwareRemoveListener(EE_REMOVE_LISTENER, false)); var zoneAwareRemoveAllListeners = callAndReturnFirstParam(makeZoneAwareRemoveAllListeners(EE_REMOVE_ALL_LISTENER, false)); var zoneAwareListeners = makeZoneAwareListeners(EE_LISTENERS); function patchEventEmitterMethods(obj) { if (obj && obj.addListener) { - patchMethod(obj, EE_ADD_LISTENER, function () { return zoneAwareAddListener$1; }); + patchMethod(obj, EE_ADD_LISTENER, function () { return zoneAwareAddListener; }); patchMethod(obj, EE_PREPEND_LISTENER, function () { return zoneAwarePrependListener; }); - patchMethod(obj, EE_REMOVE_LISTENER, function () { return zoneAwareRemoveListener$1; }); + patchMethod(obj, EE_REMOVE_LISTENER, function () { return zoneAwareRemoveListener; }); patchMethod(obj, EE_REMOVE_ALL_LISTENER, function () { return zoneAwareRemoveAllListeners; }); patchMethod(obj, EE_LISTENERS, function () { return zoneAwareListeners; }); obj[EE_ON] = obj[EE_ADD_LISTENER]; @@ -1356,8 +1675,12 @@ function patchTimer(window, setName, cancelName, nameSuffix) { function scheduleTask(task) { var data = task.data; data.args[0] = function () { - task.invoke.apply(this, arguments); - delete tasksByHandleId[data.handleId]; + try { + task.invoke.apply(this, arguments); + } + finally { + delete tasksByHandleId[data.handleId]; + } }; data.handleId = setNative.apply(window, data.args); tasksByHandleId[data.handleId] = task; @@ -1383,7 +1706,10 @@ function patchTimer(window, setName, cancelName, nameSuffix) { } // Node.js must additionally support the ref and unref functions. var handle = task.data.handleId; - if (handle.ref && handle.unref) { + // check whether handle is null, because some polyfill or browser + // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame + if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' && + typeof handle.unref === 'function') { task.ref = handle.ref.bind(handle); task.unref = handle.unref.bind(handle); } @@ -1398,7 +1724,8 @@ function patchTimer(window, setName, cancelName, nameSuffix) { patchMethod(window, cancelName, function (delegate) { return function (self, args) { var task = typeof args[0] === 'number' ? tasksByHandleId[args[0]] : args[0]; if (task && typeof task.type === 'string') { - if (task.cancelFn && task.data.isPeriodic || task.runCount === 0) { + if (task.state !== 'notScheduled' && + (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) { // Do not cancel already canceled functions task.zone.cancelTask(task); } @@ -1431,7 +1758,9 @@ if (shouldPatchGlobalTimers) { patchTimer(_global, set, clear, 'Interval'); patchTimer(_global, set, clear, 'Immediate'); } -patchNextTick(); +// patch process related methods +patchProcess(); +handleUnhandledPromiseRejection(); // Crypto var crypto; try { @@ -1439,78 +1768,52 @@ try { } catch (err) { } -// TODO(gdi2290): implement a better way to patch these methods +// use the generic patchMacroTask to patch crypto if (crypto) { - var nativeRandomBytes_1 = crypto.randomBytes; - crypto.randomBytes = function randomBytesZone(size, callback) { - if (!callback) { - return nativeRandomBytes_1(size); - } - else { - var zone = Zone.current; - var source = crypto.constructor.name + '.randomBytes'; - return nativeRandomBytes_1(size, zone.wrap(callback, source)); - } - }.bind(crypto); - var nativePbkdf2_1 = crypto.pbkdf2; - crypto.pbkdf2 = function pbkdf2Zone() { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - var fn = args[args.length - 1]; - if (typeof fn === 'function') { - var zone = Zone.current; - var source = crypto.constructor.name + '.pbkdf2'; - args[args.length - 1] = zone.wrap(fn, source); - return nativePbkdf2_1.apply(void 0, args); - } - else { - return nativePbkdf2_1.apply(void 0, args); - } - }.bind(crypto); -} -// HTTP Client -var httpClient; -try { - httpClient = require('_http_client'); + var methodNames = ['randomBytes', 'pbkdf2']; + methodNames.forEach(function (name) { + patchMacroTask(crypto, name, function (self, args) { + return { + name: 'crypto.' + name, + args: args, + callbackIndex: (args.length > 0 && typeof args[args.length - 1] === 'function') ? args.length - 1 : -1, + target: crypto + }; + }); + }); } -catch (err) { +function patchProcess() { + // patch nextTick as microTask + patchMicroTask(process, 'nextTick', function (self, args) { + return { + name: 'process.nextTick', + args: args, + callbackIndex: (args.length > 0 && typeof args[0] === 'function') ? 0 : -1, + target: process + }; + }); } -if (httpClient && httpClient.ClientRequest) { - var ClientRequest_1 = httpClient.ClientRequest.bind(httpClient); - httpClient.ClientRequest = function (options, callback) { - if (!callback) { - return new ClientRequest_1(options); - } - else { - var zone = Zone.current; - return new ClientRequest_1(options, zone.wrap(callback, 'http.ClientRequest')); - } +// handle unhandled promise rejection +function findProcessPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTask(process, evtName); + eventTasks.forEach(function (eventTask) { + // process has added unhandledrejection event listener + // trigger the event listener + if (evtName === 'unhandledRejection') { + eventTask.invoke(e.rejection, e.promise); + } + else if (evtName === 'rejectionHandled') { + eventTask.invoke(e.promise); + } + }); }; } -function patchNextTick() { - var setNative = null; - function scheduleTask(task) { - var args = task.data; - args[0] = function () { - task.invoke.apply(this, arguments); - }; - setNative.apply(process, args); - return task; - } - setNative = - patchMethod(process, 'nextTick', function (delegate) { return function (self, args) { - if (typeof args[0] === 'function') { - var zone = Zone.current; - var task = zone.scheduleMicroTask('nextTick', args[0], args, scheduleTask); - return task; - } - else { - // cause an error by calling it directly. - return delegate.apply(process, args); - } - }; }); +function handleUnhandledPromiseRejection() { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findProcessPromiseRejectionHandler('unhandledRejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findProcessPromiseRejectionHandler('rejectionHandled'); } }))); diff --git a/dist/zone.js b/dist/zone.js index a38f6e932..9820b307c 100644 --- a/dist/zone.js +++ b/dist/zone.js @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; /** @@ -19,11 +19,13 @@ * found in the LICENSE file at https://angular.io/license */ - var Zone$1 = (function (global) { if (global['Zone']) { throw new Error('Zone already loaded.'); } + var NO_ZONE = { name: 'NO ZONE' }; + var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling'; + var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; var Zone = (function () { function Zone(parent, zoneSpec) { this._properties = null; @@ -42,6 +44,17 @@ var Zone$1 = (function (global) { 'If you must load one, do so before loading zone.js.)'); } }; + Object.defineProperty(Zone, "root", { + get: function () { + var zone = Zone.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + }, + enumerable: true, + configurable: true + }); Object.defineProperty(Zone, "current", { get: function () { return _currentZoneFrame.zone; @@ -105,7 +118,7 @@ var Zone$1 = (function (global) { }; }; Zone.prototype.run = function (callback, applyThis, applyArgs, source) { - if (applyThis === void 0) { applyThis = null; } + if (applyThis === void 0) { applyThis = undefined; } if (applyArgs === void 0) { applyArgs = null; } if (source === void 0) { source = null; } _currentZoneFrame = new ZoneFrame(_currentZoneFrame, this); @@ -136,15 +149,17 @@ var Zone$1 = (function (global) { } }; Zone.prototype.runTask = function (task, applyThis, applyArgs) { - task.runCount++; if (task.zone != this) - throw new Error('A task can only be run in the zone which created it! (Creation: ' + task.zone.name + - '; Execution: ' + this.name + ')'); + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')'); + var reEntryGuard = task.state != running; + reEntryGuard && task._transitionTo(running, scheduled); + task.runCount++; var previousTask = _currentTask; _currentTask = task; _currentZoneFrame = new ZoneFrame(_currentZoneFrame, this); try { - if (task.type == 'macroTask' && task.data && !task.data.isPeriodic) { + if (task.type == macroTask && task.data && !task.data.isPeriodic) { task.cancelFn = null; } try { @@ -157,29 +172,81 @@ var Zone$1 = (function (global) { } } finally { + if (task.type == eventTask || (task.data && task.data.isPeriodic)) { + // if the task's state is notScheduled, then it has already been cancelled + // we should not reset the state to scheduled + if (task.state !== notScheduled) { + reEntryGuard && task._transitionTo(scheduled, running); + } + } + else { + task.runCount = 0; + this._updateTaskCount(task, -1); + reEntryGuard && task._transitionTo(notScheduled, running, notScheduled); + } _currentZoneFrame = _currentZoneFrame.parent; _currentTask = previousTask; } }; + Zone.prototype.scheduleTask = function (task) { + task._transitionTo(scheduling, notScheduled); + var zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task.zone = this; + task = this._zoneDelegate.scheduleTask(this, task); + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + }; Zone.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { - return this._zoneDelegate.scheduleTask(this, new ZoneTask('microTask', this, source, callback, data, customSchedule, null)); + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, null)); }; Zone.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { - return this._zoneDelegate.scheduleTask(this, new ZoneTask('macroTask', this, source, callback, data, customSchedule, customCancel)); + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); }; Zone.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { - return this._zoneDelegate.scheduleTask(this, new ZoneTask('eventTask', this, source, callback, data, customSchedule, customCancel)); + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); }; Zone.prototype.cancelTask = function (task) { - var value = this._zoneDelegate.cancelTask(this, task); - task.runCount = -1; - task.cancelFn = null; - return value; + task._transitionTo(canceling, scheduled, running); + this._zoneDelegate.cancelTask(this, task); + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = 0; + return task; + }; + Zone.prototype._updateTaskCount = function (task, count) { + var zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (var i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } }; + Zone.__symbol__ = __symbol__; return Zone; }()); - Zone.__symbol__ = __symbol__; - + var DELEGATE_ZS = { + name: '', + onHasTask: function (delegate, _, target, hasTaskState) { + return delegate.hasTask(target, hasTaskState); + }, + onScheduleTask: function (delegate, _, target, task) { + return delegate.scheduleTask(target, task); + }, + onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { + return delegate.invokeTask(target, task, applyThis, applyArgs); + }, + onCancelTask: function (delegate, _, target, task) { + return delegate.cancelTask(target, task); + } + }; var ZoneDelegate = (function () { function ZoneDelegate(zone, parentDelegate, zoneSpec) { this._taskCounts = { microTask: 0, macroTask: 0, eventTask: 0 }; @@ -222,10 +289,35 @@ var Zone$1 = (function (global) { zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); this._cancelTaskCurrZone = zoneSpec && (zoneSpec.onCancelTask ? this.zone : parentDelegate.zone); - this._hasTaskZS = zoneSpec && (zoneSpec.onHasTask ? zoneSpec : parentDelegate._hasTaskZS); - this._hasTaskDlgt = - zoneSpec && (zoneSpec.onHasTask ? parentDelegate : parentDelegate._hasTaskDlgt); - this._hasTaskCurrZone = zoneSpec && (zoneSpec.onHasTask ? this.zone : parentDelegate.zone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + var parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this.zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this.zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this.zone; + } + } } ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { return this._forkZS ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) : @@ -247,55 +339,41 @@ var Zone$1 = (function (global) { true; }; ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { - try { - if (this._scheduleTaskZS) { - return this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + var returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); } - else if (task.scheduleFn) { + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { task.scheduleFn(task); } - else if (task.type == 'microTask') { + else if (task.type == microTask) { scheduleMicroTask(task); } else { throw new Error('Task is missing scheduleFn.'); } - return task; - } - finally { - if (targetZone == this.zone) { - this._updateTaskCount(task.type, 1); - } } + return returnTask; }; ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { - try { - return this._invokeTaskZS ? - this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : - task.callback.apply(applyThis, applyArgs); - } - finally { - if (targetZone == this.zone && (task.type != 'eventTask') && - !(task.data && task.data.isPeriodic)) { - this._updateTaskCount(task.type, -1); - } - } + return this._invokeTaskZS ? + this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : + task.callback.apply(applyThis, applyArgs); }; ZoneDelegate.prototype.cancelTask = function (targetZone, task) { var value; if (this._cancelTaskZS) { value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); } - else if (!task.cancelFn) { - throw new Error('Task does not support cancellation, or is already canceled.'); - } else { value = task.cancelFn(task); } - if (targetZone == this.zone) { - // this should not be in the finally block, because exceptions assume not canceled. - this._updateTaskCount(task.type, -1); - } return value; }; ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { @@ -316,23 +394,19 @@ var Zone$1 = (function (global) { eventTask: counts.eventTask > 0, change: type }; - try { - this.hasTask(this.zone, isEmpty); - } - finally { - if (this._parentDelegate) { - this._parentDelegate._updateTaskCount(type, count); - } - } + // TODO(misko): what should happen if it throws? + this.hasTask(this.zone, isEmpty); } }; return ZoneDelegate; }()); var ZoneTask = (function () { - function ZoneTask(type, zone, source, callback, options, scheduleFn, cancelFn) { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this.zone = null; this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; this.type = type; - this.zone = zone; this.source = source; this.data = options; this.scheduleFn = scheduleFn; @@ -342,7 +416,8 @@ var Zone$1 = (function (global) { this.invoke = function () { _numberOfNestedTaskFrames++; try { - return zone.runTask(self, this, arguments); + self.runCount++; + return self.zone.runTask(self, this, arguments); } finally { if (_numberOfNestedTaskFrames == 1) { @@ -352,6 +427,29 @@ var Zone$1 = (function (global) { } }; } + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: true, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(this.type + " '" + this.source + "': can not transition to '" + toState + "', expecting state '" + fromState1 + "'" + (fromState2 ? + ' or \'' + fromState2 + '\'' : + '') + ", was '" + this._state + "'."); + } + }; ZoneTask.prototype.toString = function () { if (this.data && typeof this.data.handleId !== 'undefined') { return this.data.handleId; @@ -365,6 +463,7 @@ var Zone$1 = (function (global) { ZoneTask.prototype.toJSON = function () { return { type: this.type, + state: this.state, source: this.source, data: this.data, zone: this.zone.name, @@ -415,12 +514,26 @@ var Zone$1 = (function (global) { _microTaskQueue.push(task); } function consoleError(e) { + if (Zone[__symbol__('ignoreConsoleErrorUncaughtError')]) { + return; + } var rejection = e && e.rejection; if (rejection) { console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); } console.error(e); } + function handleUnhandledRejection(e) { + consoleError(e); + try { + var handler = Zone[__symbol__('unhandledPromiseRejectionHandler')]; + if (handler && typeof handler === 'function') { + handler.apply(this, [e]); + } + } + catch (err) { + } + } function drainMicroTaskQueue() { if (!_isDrainingMicrotaskQueue) { _isDrainingMicrotaskQueue = true; @@ -432,21 +545,21 @@ var Zone$1 = (function (global) { try { task.zone.runTask(task, null, null); } - catch (e) { - consoleError(e); + catch (error) { + consoleError(error); } } } while (_uncaughtPromiseErrors.length) { - var _loop_1 = function () { + var _loop_1 = function() { var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); try { uncaughtPromiseError.zone.runGuarded(function () { throw uncaughtPromiseError; }); } - catch (e) { - consoleError(e); + catch (error) { + handleUnhandledRejection(error); } }; while (_uncaughtPromiseErrors.length) { @@ -474,24 +587,75 @@ var Zone$1 = (function (global) { var REJECTED_NO_CATCH = 0; function makeResolver(promise, state) { return function (v) { - resolvePromise(promise, state, v); + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } // Do not return value or you will break the Promise spec. }; } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + // Promise Resolution function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError('Promise resolved with itself'); + } if (promise[symbolState] === UNRESOLVED) { - if (value instanceof ZoneAwarePromise && value.hasOwnProperty(symbolState) && - value.hasOwnProperty(symbolValue) && value[symbolState] !== UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { clearRejectedNoCatch(value); resolvePromise(promise, value[symbolState], value[symbolValue]); } - else if (isThenable(value)) { - value.then(makeResolver(promise, state), makeResolver(promise, false)); + else if (state !== REJECTED && typeof then === 'function') { + try { + then.apply(value, [ + onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false)) + ]); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } } else { promise[symbolState] = state; var queue = promise[symbolValue]; promise[symbolValue] = value; + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + value[__symbol__('currentTask')] = Zone.currentTask; + } for (var i = 0; i < queue.length;) { scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); } @@ -501,8 +665,8 @@ var Zone$1 = (function (global) { throw new Error('Uncaught (in promise): ' + value + (value && value.stack ? '\n' + value.stack : '')); } - catch (e) { - var error_1 = e; + catch (err) { + var error_1 = err; error_1.rejection = value; error_1.promise = promise; error_1.zone = Zone.current; @@ -518,21 +682,35 @@ var Zone$1 = (function (global) { } function clearRejectedNoCatch(promise) { if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[__symbol__('rejectionHandledHandler')]; + if (handler && typeof handler === 'function') { + handler.apply(this, [{ rejection: promise[symbolValue], promise: promise }]); + } + } + catch (err) { + } promise[symbolState] = REJECTED; for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { if (promise === _uncaughtPromiseErrors[i].promise) { _uncaughtPromiseErrors.splice(i, 1); - break; } } } } function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { clearRejectedNoCatch(promise); - var delegate = promise[symbolState] ? onFulfilled || forwardResolution : onRejected || forwardRejection; + var delegate = promise[symbolState] ? + (typeof onFulfilled === 'function') ? onFulfilled : forwardResolution : + (typeof onRejected === 'function') ? onRejected : forwardRejection; zone.scheduleMicroTask(source, function () { try { - resolvePromise(chainPromise, true, zone.run(delegate, null, [promise[symbolValue]])); + resolvePromise(chainPromise, true, zone.run(delegate, undefined, [promise[symbolValue]])); } catch (error) { resolvePromise(chainPromise, false, error); @@ -550,8 +728,8 @@ var Zone$1 = (function (global) { try { executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED)); } - catch (e) { - resolvePromise(promise, false, e); + catch (error) { + resolvePromise(promise, false, error); } } ZoneAwarePromise.toString = function () { @@ -634,38 +812,41 @@ var Zone$1 = (function (global) { ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; ZoneAwarePromise['race'] = ZoneAwarePromise.race; ZoneAwarePromise['all'] = ZoneAwarePromise.all; - var NativePromise = global[__symbol__('Promise')] = global['Promise']; + var NativePromise = global[symbolPromise] = global['Promise']; global['Promise'] = ZoneAwarePromise; - function patchThen(NativePromise) { - var NativePromiseProtototype = NativePromise.prototype; - var NativePromiseThen = NativePromiseProtototype[__symbol__('then')] = - NativePromiseProtototype.then; - NativePromiseProtototype.then = function (onResolve, onReject) { - var nativePromise = this; - return new ZoneAwarePromise(function (resolve, reject) { - NativePromiseThen.call(nativePromise, resolve, reject); - }) - .then(onResolve, onReject); + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); }; + Ctor[symbolThenPatched] = true; } - if (NativePromise) { - patchThen(NativePromise); - if (typeof global['fetch'] !== 'undefined') { - var fetchPromise = void 0; - try { - // In MS Edge this throws - fetchPromise = global['fetch'](); - } - catch (e) { - // In Chrome this throws instead. - fetchPromise = global['fetch']('about:blank'); + function zoneify(fn) { + return function () { + var resultPromise = fn.apply(this, arguments); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; } - // ignore output to prevent error; - fetchPromise.then(function () { return null; }, function () { return null; }); - if (fetchPromise.constructor != NativePromise && - fetchPromise.constructor != ZoneAwarePromise) { - patchThen(fetchPromise.constructor); + var Ctor = resultPromise.constructor; + if (!Ctor[symbolThenPatched]) { + patchThen(Ctor); } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + var fetch = global['fetch']; + if (typeof fetch == 'function') { + global['fetch'] = zoneify(fetch); } } // This is not part of public API, but it is usefull for tests, so we expose it. @@ -855,6 +1036,24 @@ var Zone$1 = (function (global) { ZoneAwareError.prototype = NativeError.prototype; ZoneAwareError[Zone.__symbol__('blacklistedStackFrames')] = blackListedStackFrames; ZoneAwareError[stackRewrite] = false; + // those properties need special handling + var specialPropertyNames = ['stackTraceLimit', 'captureStackTrace', 'prepareStackTrace']; + // those properties of NativeError should be set to ZoneAwareError + var nativeErrorProperties = Object.keys(NativeError); + if (nativeErrorProperties) { + nativeErrorProperties.forEach(function (prop) { + if (specialPropertyNames.filter(function (sp) { return sp === prop; }).length === 0) { + Object.defineProperty(ZoneAwareError, prop, { + get: function () { + return NativeError[prop]; + }, + set: function (value) { + NativeError[prop] = value; + } + }); + } + }); + } if (NativeError.hasOwnProperty('stackTraceLimit')) { // Extend default stack limit as we will be removing few frames. NativeError.stackTraceLimit = Math.max(NativeError.stackTraceLimit, 15); @@ -980,9 +1179,9 @@ var Zone$1 = (function (global) { /** * Suppress closure compiler errors about unknown 'Zone' variable * @fileoverview - * @suppress {undefinedVars} + * @suppress {undefinedVars,globalThis} */ -var zoneSymbol = function (n) { return "__zone_symbol__" + n; }; +var zoneSymbol = function (n) { return ("__zone_symbol__" + n); }; var _global$1 = typeof window === 'object' && window || typeof self === 'object' && self || global; function bindArguments(args, source) { for (var i = args.length - 1; i >= 0; i--) { @@ -994,7 +1193,7 @@ function bindArguments(args, source) { } function patchPrototype(prototype, fnNames) { var source = prototype.constructor['name']; - var _loop_1 = function (i) { + var _loop_1 = function(i) { var name_1 = fnNames[i]; var delegate = prototype[name_1]; if (delegate) { @@ -1013,6 +1212,10 @@ var isWebWorker = (typeof WorkerGlobalScope !== 'undefined' && self instanceof W var isNode = (!('nw' in _global$1) && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'); var isBrowser = !isNode && !isWebWorker && !!(typeof window !== 'undefined' && window['HTMLElement']); +// we are in electron of nw, so we are both browser and nodejs +var isMix = typeof process !== 'undefined' && + {}.toString.call(process) === '[object process]' && !isWebWorker && + !!(typeof window !== 'undefined' && window['HTMLElement']); function patchProperty(obj, prop) { var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; var originalDesc = Object.getOwnPropertyDescriptor(obj, 'original' + prop); @@ -1028,7 +1231,7 @@ function patchProperty(obj, prop) { delete desc.value; // substr(2) cuz 'onclick' -> 'click', etc var eventName = prop.substr(2); - var _prop = '_' + prop; + var _prop = zoneSymbol('_' + prop); desc.set = function (fn) { if (this[_prop]) { this.removeEventListener(eventName, this[_prop]); @@ -1112,24 +1315,6 @@ function findExistingRegisteredTask(target, handler, name, capture, remove) { } return null; } -function findAllExistingRegisteredTasks(target, name, capture, remove) { - var eventTasks = target[EVENT_TASKS]; - if (eventTasks) { - var result = []; - for (var i = eventTasks.length - 1; i >= 0; i--) { - var eventTask = eventTasks[i]; - var data = eventTask.data; - if (data.eventName === name && data.useCapturing === capture) { - result.push(eventTask); - if (remove) { - eventTasks.splice(i, 1); - } - } - } - return result; - } - return null; -} function attachRegisteredEvent(target, eventTask, isPrepend) { var eventTasks = target[EVENT_TASKS]; if (!eventTasks) { @@ -1205,7 +1390,7 @@ function makeZoneAwareAddListener(addFnName, removeFnName, useCapturingParam, al // will fail tests prematurely. validZoneHandler = data.handler && data.handler.toString() === '[object FunctionWrapper]'; } - catch (e) { + catch (error) { // Returning nothing here is fine, because objects in a cross-site context are unusable return; } @@ -1331,7 +1516,7 @@ function createNamedFn(name, delegate) { try { return (Function('f', "return function " + name + "(){return f(this, arguments)}"))(delegate); } - catch (e) { + catch (error) { // if we fail, we must be CSP, just return delegate. return function () { return delegate(this, arguments); @@ -1355,7 +1540,26 @@ function patchMethod(target, name, patchFn) { } return delegate; } -// TODO: support cancel task later if necessary +// TODO: @JiaLiPassion, support cancel task later if necessary + + +function findEventTask(target, evtName) { + var eventTasks = target[zoneSymbol('eventTasks')]; + var result = []; + if (eventTasks) { + for (var i = 0; i < eventTasks.length; i++) { + var eventTask = eventTasks[i]; + var data = eventTask.data; + var eventName = data && data.eventName; + if (eventName === evtName) { + result.push(eventTask); + } + } + } + return result; +} +Zone[zoneSymbol('patchEventTargetMethods')] = patchEventTargetMethods; +Zone[zoneSymbol('patchOnProperties')] = patchOnProperties; /** * @license @@ -1373,8 +1577,12 @@ function patchTimer(window, setName, cancelName, nameSuffix) { function scheduleTask(task) { var data = task.data; data.args[0] = function () { - task.invoke.apply(this, arguments); - delete tasksByHandleId[data.handleId]; + try { + task.invoke.apply(this, arguments); + } + finally { + delete tasksByHandleId[data.handleId]; + } }; data.handleId = setNative.apply(window, data.args); tasksByHandleId[data.handleId] = task; @@ -1400,7 +1608,10 @@ function patchTimer(window, setName, cancelName, nameSuffix) { } // Node.js must additionally support the ref and unref functions. var handle = task.data.handleId; - if (handle.ref && handle.unref) { + // check whether handle is null, because some polyfill or browser + // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame + if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' && + typeof handle.unref === 'function') { task.ref = handle.ref.bind(handle); task.unref = handle.unref.bind(handle); } @@ -1415,7 +1626,8 @@ function patchTimer(window, setName, cancelName, nameSuffix) { patchMethod(window, cancelName, function (delegate) { return function (self, args) { var task = typeof args[0] === 'number' ? tasksByHandleId[args[0]] : args[0]; if (task && typeof task.type === 'string') { - if (task.cancelFn && task.data.isPeriodic || task.runCount === 0) { + if (task.state !== 'notScheduled' && + (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) { // Do not cancel already canceled functions task.zone.cancelTask(task); } @@ -1500,7 +1712,7 @@ function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { try { return _defineProperty(obj, prop, desc); } - catch (e) { + catch (error) { if (desc.configurable) { // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's // retry with the original flag value @@ -1513,19 +1725,19 @@ function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { try { return _defineProperty(obj, prop, desc); } - catch (e) { + catch (error) { var descJson = null; try { descJson = JSON.stringify(desc); } - catch (e) { + catch (error) { descJson = descJson.toString(); } - console.log("Attempting to configure '" + prop + "' with descriptor '" + descJson + "' on object '" + obj + "' and got error, giving up: " + e); + console.log("Attempting to configure '" + prop + "' with descriptor '" + descJson + "' on object '" + obj + "' and got error, giving up: " + error); } } else { - throw e; + throw error; } } } @@ -1612,7 +1824,7 @@ function apply(_global) { var eventNames = 'copy cut paste abort blur focus canplay canplaythrough change click contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop durationchange emptied ended input invalid keydown keypress keyup load loadeddata loadedmetadata loadstart message mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup pause play playing progress ratechange reset scroll seeked seeking select show stalled submit suspend timeupdate volumechange waiting mozfullscreenchange mozfullscreenerror mozpointerlockchange mozpointerlockerror error webglcontextrestored webglcontextlost webglcontextcreationerror' .split(' '); function propertyDescriptorPatch(_global) { - if (isNode) { + if (isNode && !isMix) { return; } var supportsWebSocket = typeof WebSocket !== 'undefined'; @@ -1644,7 +1856,7 @@ function propertyDescriptorPatch(_global) { } } function canPatchViaPropertyDescriptor() { - if (isBrowser && !Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && + if ((isBrowser || isMix) && !Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && typeof Element !== 'undefined') { // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364 // IDL interface attributes are not configurable @@ -1676,7 +1888,7 @@ var unboundKey = zoneSymbol('unbound'); // for `onwhatever` properties and replace them with zone-bound functions // - Chrome (for now) function patchViaCapturingAllTheEvents() { - var _loop_1 = function (i) { + var _loop_1 = function(i) { var property = eventNames[i]; var onproperty = 'on' + property; self.addEventListener(property, function (event) { @@ -1711,7 +1923,7 @@ function patchViaCapturingAllTheEvents() { * found in the LICENSE file at https://angular.io/license */ function registerElementPatch(_global) { - if (!isBrowser || !('registerElement' in _global.document)) { + if ((!isBrowser && !isMix) || !('registerElement' in _global.document)) { return; } var _registerElement = document.registerElement; @@ -1792,7 +2004,9 @@ function patchXHR(window) { } var newListener = data.target[XHR_LISTENER] = function () { if (data.target.readyState === data.target.DONE) { - if (!data.aborted && self[XHR_SCHEDULED]) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && self[XHR_SCHEDULED] && task.state === 'scheduled') { task.invoke(); } } @@ -1849,6 +2063,26 @@ function patchXHR(window) { if (_global['navigator'] && _global['navigator'].geolocation) { patchPrototype(_global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); } +// handle unhandled promise rejection +function findPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTask(_global, evtName); + eventTasks.forEach(function (eventTask) { + // windows has added unhandledrejection event listener + // trigger the event listener + var PromiseRejectionEvent = _global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + var evt = new PromiseRejectionEvent(evtName, { promise: e.promise, reason: e.rejection }); + eventTask.invoke(evt); + } + }); + }; +} +if (_global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = findPromiseRejectionHandler('rejectionhandled'); +} /** * @license diff --git a/dist/zone.js.d.ts b/dist/zone.js.d.ts index c66bdaaec..afd564d69 100644 --- a/dist/zone.js.d.ts +++ b/dist/zone.js.d.ts @@ -212,9 +212,43 @@ interface Zone { * @returns {*} */ runTask(task: Task, applyThis?: any, applyArgs?: any): any; + /** + * Schedule a MicroTask. + * + * @param source + * @param callback + * @param data + * @param customSchedule + */ scheduleMicroTask(source: string, callback: Function, data?: TaskData, customSchedule?: (task: Task) => void): MicroTask; + /** + * Schedule a MacroTask. + * + * @param source + * @param callback + * @param data + * @param customSchedule + * @param customCancel + */ scheduleMacroTask(source: string, callback: Function, data: TaskData, customSchedule: (task: Task) => void, customCancel: (task: Task) => void): MacroTask; + /** + * Schedule an EventTask. + * + * @param source + * @param callback + * @param data + * @param customSchedule + * @param customCancel + */ scheduleEventTask(source: string, callback: Function, data: TaskData, customSchedule: (task: Task) => void, customCancel: (task: Task) => void): EventTask; + /** + * Schedule an existing Task. + * + * Useful for rescheduling a task which was already canceled. + * + * @param task + */ + scheduleTask(task: T): T; /** * Allows the zone to intercept canceling of scheduled Task. * @@ -241,6 +275,10 @@ interface ZoneType { * Verify that Zone has been correctly patched. Specifically that Promise is zone aware. */ assertZonePatched(): any; + /** + * Return the root zone. + */ + root: Zone; } /** * Provides a way to configure the interception of zone events. @@ -381,6 +419,10 @@ declare type HasTaskState = { * Task type: `microTask`, `macroTask`, `eventTask`. */ declare type TaskType = string; +/** + * Task type: `notScheduled`, `scheduling`, `scheduled`, `running`, `canceling`. + */ +declare type TaskState = string; /** */ interface TaskData { @@ -419,6 +461,10 @@ interface Task { * Task type: `microTask`, `macroTask`, `eventTask`. */ type: TaskType; + /** + * Task state: `notScheduled`, `scheduling`, `scheduled`, `running`, `canceling`. + */ + state: TaskState; /** * Debug string representing the API which requested the scheduling of the task. */ @@ -459,6 +505,12 @@ interface Task { * Number of times the task has been executed, or -1 if canceled. */ runCount: number; + /** + * Cancel the scheduling request. This method can be called from `ZoneSpec.onScheduleTask` to + * cancel the current scheduling interception. Once canceled the task can be discarted or + * rescheduled using `Zone.scheduleTask` on a different zone. + */ + cancelScheduleRequest(): void; } interface MicroTask extends Task { } diff --git a/dist/zone.min.js b/dist/zone.min.js index 3c69b38fe..b543a3338 100644 --- a/dist/zone.min.js +++ b/dist/zone.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t():"function"==typeof define&&define.amd?define(t):t()}(this,function(){"use strict";function e(e,t){for(var n=e.length-1;n>=0;n--)"function"==typeof e[n]&&(e[n]=Zone.current.wrap(e[n],t+"_"+n));return e}function t(t,n){for(var r=t.constructor.name,o=function(o){var a=n[o],i=t[a];i&&(t[a]=function(t){return function(){return t.apply(this,e(arguments,r+"."+a))}}(i))},a=0;a1?new t(e,n):new t(e),i=Object.getOwnPropertyDescriptor(a,"onmessage");return i&&i.configurable===!1?(o=Object.create(a),["addEventListener","removeEventListener","send","close"].forEach(function(e){o[e]=function(){return a[e].apply(a,arguments)}})):o=a,r(o,["close","error","message","open"]),o};for(var n in t)e.WebSocket[n]=t[n]}function m(e){if(!P){var t="undefined"!=typeof WebSocket;T()?(j&&r(HTMLElement.prototype,B),r(XMLHttpRequest.prototype,null),"undefined"!=typeof IDBIndex&&(r(IDBIndex.prototype,null),r(IDBRequest.prototype,null),r(IDBOpenDBRequest.prototype,null),r(IDBDatabase.prototype,null),r(IDBTransaction.prototype,null),r(IDBCursor.prototype,null)),t&&r(WebSocket.prototype,null)):(w(),u("XMLHttpRequest"),t&&b(e))}}function T(){if(j&&!Object.getOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&"undefined"!=typeof Element){var e=Object.getOwnPropertyDescriptor(Element.prototype,"onclick");if(e&&!e.configurable)return!1}var t=Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype,"onreadystatechange");Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",{enumerable:!0,configurable:!0,get:function(){return!0}});var n=new XMLHttpRequest,r=!!n.onreadystatechange;return Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",t||{}),r}function w(){for(var e=function(e){var t=B[e],n="on"+t;self.addEventListener(t,function(e){var t,r,o=e.target;for(r=o?o.constructor.name+"."+n:"unknown."+n;o;)o[n]&&!o[n][N]&&(t=Zone.current.wrap(o[n],r),t[N]=o[n],o[n]=t),o=o.parentElement},!0)},t=0;t "+r.zone.name+"]",r=r.parent):r=null:n[o]+=" ["+r.zone.name+"]"}}e.stack=e.zoneAwareStack=n.join("\n")}return Object.defineProperties(this,K(Object.getPrototypeOf(this))),this}if(e.Zone)throw new Error("Zone already loaded.");var v=function(){function t(e,t){this._properties=null,this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new k(this,this._parent&&this._parent._zoneDelegate,t)}return t.assertZonePatched=function(){if(e.Promise!==F)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(t,"current",{get:function(){return w.zone},enumerable:!0,configurable:!0}),Object.defineProperty(t,"currentTask",{get:function(){return _},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"name",{get:function(){return this._name},enumerable:!0,configurable:!0}),t.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},t.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},t.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},t.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},t.prototype.run=function(e,t,n,r){void 0===t&&(t=null),void 0===n&&(n=null),void 0===r&&(r=null),w=new y(w,this);try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{w=w.parent}},t.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),void 0===n&&(n=null),void 0===r&&(r=null),w=new y(w,this);try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(o){if(this._zoneDelegate.handleError(this,o))throw o}}finally{w=w.parent}},t.prototype.runTask=function(e,t,n){if(e.runCount++,e.zone!=this)throw new Error("A task can only be run in the zone which created it! (Creation: "+e.zone.name+"; Execution: "+this.name+")");var r=_;_=e,w=new y(w,this);try{"macroTask"==e.type&&e.data&&!e.data.isPeriodic&&(e.cancelFn=null);try{return this._zoneDelegate.invokeTask(this,e,t,n)}catch(o){if(this._zoneDelegate.handleError(this,o))throw o}}finally{w=w.parent,_=r}},t.prototype.scheduleMicroTask=function(e,t,n,r){return this._zoneDelegate.scheduleTask(this,new g("microTask",this,e,t,n,r,null))},t.prototype.scheduleMacroTask=function(e,t,n,r,o){return this._zoneDelegate.scheduleTask(this,new g("macroTask",this,e,t,n,r,o))},t.prototype.scheduleEventTask=function(e,t,n,r,o){return this._zoneDelegate.scheduleTask(this,new g("eventTask",this,e,t,n,r,o))},t.prototype.cancelTask=function(e){var t=this._zoneDelegate.cancelTask(this,e);return e.runCount=-1,e.cancelFn=null,t},t}();v.__symbol__=t;var k=function(){function e(e,t,n){this._taskCounts={microTask:0,macroTask:0,eventTask:0},this.zone=e,this._parentDelegate=t,this._forkZS=n&&(n&&n.onFork?n:t._forkZS),this._forkDlgt=n&&(n.onFork?t:t._forkDlgt),this._forkCurrZone=n&&(n.onFork?this.zone:t.zone),this._interceptZS=n&&(n.onIntercept?n:t._interceptZS),this._interceptDlgt=n&&(n.onIntercept?t:t._interceptDlgt),this._interceptCurrZone=n&&(n.onIntercept?this.zone:t.zone),this._invokeZS=n&&(n.onInvoke?n:t._invokeZS),this._invokeDlgt=n&&(n.onInvoke?t:t._invokeDlgt),this._invokeCurrZone=n&&(n.onInvoke?this.zone:t.zone),this._handleErrorZS=n&&(n.onHandleError?n:t._handleErrorZS),this._handleErrorDlgt=n&&(n.onHandleError?t:t._handleErrorDlgt),this._handleErrorCurrZone=n&&(n.onHandleError?this.zone:t.zone),this._scheduleTaskZS=n&&(n.onScheduleTask?n:t._scheduleTaskZS),this._scheduleTaskDlgt=n&&(n.onScheduleTask?t:t._scheduleTaskDlgt),this._scheduleTaskCurrZone=n&&(n.onScheduleTask?this.zone:t.zone),this._invokeTaskZS=n&&(n.onInvokeTask?n:t._invokeTaskZS),this._invokeTaskDlgt=n&&(n.onInvokeTask?t:t._invokeTaskDlgt),this._invokeTaskCurrZone=n&&(n.onInvokeTask?this.zone:t.zone),this._cancelTaskZS=n&&(n.onCancelTask?n:t._cancelTaskZS),this._cancelTaskDlgt=n&&(n.onCancelTask?t:t._cancelTaskDlgt),this._cancelTaskCurrZone=n&&(n.onCancelTask?this.zone:t.zone),this._hasTaskZS=n&&(n.onHasTask?n:t._hasTaskZS),this._hasTaskDlgt=n&&(n.onHasTask?t:t._hasTaskDlgt),this._hasTaskCurrZone=n&&(n.onHasTask?this.zone:t.zone)}return e.prototype.fork=function(e,t){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,e,t):new v(e,t)},e.prototype.intercept=function(e,t,n){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,e,t,n):t},e.prototype.invoke=function(e,t,n,r,o){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,e,t,n,r,o):t.apply(n,r)},e.prototype.handleError=function(e,t){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,e,t)},e.prototype.scheduleTask=function(e,t){try{if(this._scheduleTaskZS)return this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,e,t);if(t.scheduleFn)t.scheduleFn(t);else{if("microTask"!=t.type)throw new Error("Task is missing scheduleFn.");r(t)}return t}finally{e==this.zone&&this._updateTaskCount(t.type,1)}},e.prototype.invokeTask=function(e,t,n,r){try{return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,e,t,n,r):t.callback.apply(n,r)}finally{e!=this.zone||"eventTask"==t.type||t.data&&t.data.isPeriodic||this._updateTaskCount(t.type,-1)}},e.prototype.cancelTask=function(e,t){var n;if(this._cancelTaskZS)n=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,e,t);else{if(!t.cancelFn)throw new Error("Task does not support cancellation, or is already canceled.");n=t.cancelFn(t)}return e==this.zone&&this._updateTaskCount(t.type,-1),n},e.prototype.hasTask=function(e,t){return this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,e,t)},e.prototype._updateTaskCount=function(e,t){var n=this._taskCounts,r=n[e],o=n[e]=r+t;if(o<0)throw new Error("More tasks executed then were scheduled.");if(0==r||0==o){var a={microTask:n.microTask>0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e};try{this.hasTask(this.zone,a)}finally{this._parentDelegate&&this._parentDelegate._updateTaskCount(e,t)}}},e}(),g=function(){function e(e,t,n,r,o,i,s){this.runCount=0,this.type=e,this.zone=t,this.source=n,this.data=o,this.scheduleFn=i,this.cancelFn=s,this.callback=r;var c=this;this.invoke=function(){D++;try{return t.runTask(c,this,arguments)}finally{1==D&&a(),D--}}}return e.prototype.toString=function(){return this.data&&"undefined"!=typeof this.data.handleId?this.data.handleId:Object.prototype.toString.call(this)},e.prototype.toJSON=function(){return{type:this.type,source:this.source,data:this.data,zone:this.zone.name,invoke:this.invoke,scheduleFn:this.scheduleFn,cancelFn:this.cancelFn,runCount:this.runCount,callback:this.callback}},e}(),y=function(){function e(e,t){this.parent=e,this.zone=t}return e}(),b=t("setTimeout"),m=t("Promise"),T=t("then"),w=new y(null,new v(null,null)),_=null,S=[],O=!1,E=[],D=0,P=t("state"),j=t("value"),Z="Promise.then",z=null,C=!0,I=!1,L=0,F=function(){function e(t){var n=this;if(!(n instanceof e))throw new Error("Must be an instanceof Promise.");n[P]=z,n[j]=[];try{t&&t(u(n,C),u(n,I))}catch(r){l(n,!1,r)}}return e.toString=function(){return"function ZoneAwarePromise() { [native code] }"},e.resolve=function(e){return l(new this(null),C,e)},e.reject=function(e){return l(new this(null),I,e)},e.race=function(e){function t(e){a&&(a=r(e))}function n(e){a&&(a=o(e))}for(var r,o,a=new this(function(e,t){n=[e,t],r=n[0],o=n[1];var n}),s=0,c=e;s=0;n--)"function"==typeof e[n]&&(e[n]=Zone.current.wrap(e[n],t+"_"+n));return e}function t(t,n){for(var r=t.constructor.name,o=function(o){var a=n[o],i=t[a];i&&(t[a]=function(t){return function(){return t.apply(this,e(arguments,r+"."+a))}}(i))},a=0;a1?new t(e,n):new t(e),i=Object.getOwnPropertyDescriptor(a,"onmessage");return i&&i.configurable===!1?(o=Object.create(a),["addEventListener","removeEventListener","send","close"].forEach(function(e){o[e]=function(){return a[e].apply(a,arguments)}})):o=a,r(o,["close","error","message","open"]),o};for(var n in t)e.WebSocket[n]=t[n]}function m(e){if(!P||z){var t="undefined"!=typeof WebSocket;_()?(C&&r(HTMLElement.prototype,X),r(XMLHttpRequest.prototype,null),"undefined"!=typeof IDBIndex&&(r(IDBIndex.prototype,null),r(IDBRequest.prototype,null),r(IDBOpenDBRequest.prototype,null),r(IDBDatabase.prototype,null),r(IDBTransaction.prototype,null),r(IDBCursor.prototype,null)),t&&r(WebSocket.prototype,null)):(w(),u("XMLHttpRequest"),t&&b(e))}}function _(){if((C||z)&&!Object.getOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&"undefined"!=typeof Element){var e=Object.getOwnPropertyDescriptor(Element.prototype,"onclick");if(e&&!e.configurable)return!1}var t=Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype,"onreadystatechange");Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",{enumerable:!0,configurable:!0,get:function(){return!0}});var n=new XMLHttpRequest,r=!!n.onreadystatechange;return Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",t||{}),r}function w(){for(var e=function(e){var t=X[e],n="on"+t;self.addEventListener(t,function(e){var t,r,o=e.target;for(r=o?o.constructor.name+"."+n:"unknown."+n;o;)o[n]&&!o[n][G]&&(t=Zone.current.wrap(o[n],r),t[G]=o[n],o[n]=t),o=o.parentElement},!0)},t=0;t "+r.zone.name+"]",r=r.parent):r=null:n[o]+=" ["+r.zone.name+"]"}}e.stack=e.zoneAwareStack=n.join("\n")}return Object.defineProperties(this,se(Object.getPrototypeOf(this))),this}if(e.Zone)throw new Error("Zone already loaded.");var g={name:"NO ZONE"},y="notScheduled",T="scheduling",b="scheduled",m="running",_="canceling",w="microTask",S="macroTask",O="eventTask",E=function(){function n(e,t){this._properties=null,this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new Z(this,this._parent&&this._parent._zoneDelegate,t)}return n.assertZonePatched=function(){if(e.Promise!==K)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(n,"root",{get:function(){for(var e=n.current;e.parent;)e=e.parent;return e},enumerable:!0,configurable:!0}),Object.defineProperty(n,"current",{get:function(){return L.zone},enumerable:!0,configurable:!0}),Object.defineProperty(n,"currentTask",{get:function(){return F},enumerable:!0,configurable:!0}),Object.defineProperty(n.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(n.prototype,"name",{get:function(){return this._name},enumerable:!0,configurable:!0}),n.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},n.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},n.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},n.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},n.prototype.run=function(e,t,n,r){void 0===t&&(t=void 0),void 0===n&&(n=null),void 0===r&&(r=null),L=new P(L,this);try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{L=L.parent}},n.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),void 0===n&&(n=null),void 0===r&&(r=null),L=new P(L,this);try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(o){if(this._zoneDelegate.handleError(this,o))throw o}}finally{L=L.parent}},n.prototype.runTask=function(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||g).name+"; Execution: "+this.name+")");var r=e.state!=m;r&&e._transitionTo(m,b),e.runCount++;var o=F;F=e,L=new P(L,this);try{e.type==S&&e.data&&!e.data.isPeriodic&&(e.cancelFn=null);try{return this._zoneDelegate.invokeTask(this,e,t,n)}catch(a){if(this._zoneDelegate.handleError(this,a))throw a}}finally{e.type==O||e.data&&e.data.isPeriodic?e.state!==y&&r&&e._transitionTo(b,m):(e.runCount=0,this._updateTaskCount(e,-1),r&&e._transitionTo(y,m,y)),L=L.parent,F=o}},n.prototype.scheduleTask=function(e){e._transitionTo(T,y);var t=[];return e._zoneDelegates=t,e.zone=this,e=this._zoneDelegate.scheduleTask(this,e),e._zoneDelegates===t&&this._updateTaskCount(e,1),e.state==T&&e._transitionTo(b,T),e},n.prototype.scheduleMicroTask=function(e,t,n,r){return this.scheduleTask(new D(w,e,t,n,r,null))},n.prototype.scheduleMacroTask=function(e,t,n,r,o){return this.scheduleTask(new D(S,e,t,n,r,o))},n.prototype.scheduleEventTask=function(e,t,n,r,o){return this.scheduleTask(new D(O,e,t,n,r,o))},n.prototype.cancelTask=function(e){return e._transitionTo(_,b,m),this._zoneDelegate.cancelTask(this,e),this._updateTaskCount(e,-1),e._transitionTo(y,_),e.runCount=0,e},n.prototype._updateTaskCount=function(e,t){var n=e._zoneDelegates;t==-1&&(e._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e};this.hasTask(this.zone,a)}},e}(),D=function(){function e(e,t,n,r,o,a){this.zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=e,this.source=t,this.data=r,this.scheduleFn=o,this.cancelFn=a,this.callback=n;var s=this;this.invoke=function(){x++;try{return s.runCount++,s.zone.runTask(s,this,arguments)}finally{1==x&&i(),x--}}}return Object.defineProperty(e.prototype,"state",{get:function(){return this._state},enumerable:!0,configurable:!0}),e.prototype.cancelScheduleRequest=function(){this._transitionTo(y,T)},e.prototype._transitionTo=function(e,t,n){if(this._state!==t&&this._state!==n)throw new Error(this.type+" '"+this.source+"': can not transition to '"+e+"', expecting state '"+t+"'"+(n?" or '"+n+"'":"")+", was '"+this._state+"'.");this._state=e,e==y&&(this._zoneDelegates=null)},e.prototype.toString=function(){return this.data&&"undefined"!=typeof this.data.handleId?this.data.handleId:Object.prototype.toString.call(this)},e.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,data:this.data,zone:this.zone.name,invoke:this.invoke,scheduleFn:this.scheduleFn,cancelFn:this.cancelFn,runCount:this.runCount,callback:this.callback}},e}(),P=function(){function e(e,t){this.parent=e,this.zone=t}return e}(),C=t("setTimeout"),z=t("Promise"),I=t("then"),L=new P(null,new E(null,null)),F=null,M=[],H=!1,R=[],x=0,q=t("state"),N=t("value"),A="Promise.then",B=null,W=!0,X=!1,G=0,U=function(){var e=!1;return function(t){return function(){e||(e=!0,t.apply(null,arguments))}}},K=function(){function e(t){var n=this;if(!(n instanceof e))throw new Error("Must be an instanceof Promise.");n[q]=B,n[N]=[];try{t&&t(l(n,W),l(n,X))}catch(r){f(n,!1,r)}}return e.toString=function(){return"function ZoneAwarePromise() { [native code] }"},e.resolve=function(e){return f(new this(null),W,e)},e.reject=function(e){return f(new this(null),X,e)},e.race=function(e){function t(e){a&&(a=r(e))}function n(e){a&&(a=o(e))}for(var r,o,a=new this(function(e,t){n=[e,t],r=n[0],o=n[1];var n}),i=0,c=e;i