123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- /** @license MIT License (c) copyright 2010-2014 original author or authors */
- /** @author Brian Cavalier */
- /** @author John Hann */
- (function(define) { 'use strict';
- define(function(require) {
- var defaultStackJumpSeparator = 'from execution context:';
- var defaultStackFilter = /[\s\(\/\\](node|module|timers)\.js:|when([\/\\]{1,2}(lib|monitor|es6-shim)[\/\\]{1,2}|\.js)|(new\sPromise)\b|(\b(PromiseMonitor|ConsoleReporter|Scheduler|RunHandlerTask|ProgressTask|Promise|.*Handler)\.[\w_]\w\w+\b)|\b(tryCatch\w+|getHandler\w*)\b/i;
- var setTimer = require('../lib/env').setTimer;
- var error = require('./error');
- var executionContext = [];
- function PromiseMonitor(reporter) {
- this.logDelay = 0;
- this.stackFilter = defaultStackFilter;
- this.stackJumpSeparator = defaultStackJumpSeparator;
- this.filterDuplicateFrames = true;
- this._reporter = reporter;
- if(typeof reporter.configurePromiseMonitor === 'function') {
- reporter.configurePromiseMonitor(this);
- }
- this._traces = [];
- this._traceTask = 0;
- var self = this;
- this._doLogTraces = function() {
- self._logTraces();
- };
- }
- PromiseMonitor.prototype.monitor = function(Promise) {
- var self = this;
- Promise.createContext = function(p, context) {
- p.context = self.createContext(p, context);
- };
- Promise.enterContext = function(p) {
- executionContext.push(p.context);
- };
- Promise.exitContext = function() {
- executionContext.pop();
- };
- Promise.onPotentiallyUnhandledRejection = function(rejection, extraContext) {
- return self.addTrace(rejection, extraContext);
- };
- Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) {
- return self.removeTrace(rejection);
- };
- Promise.onFatalRejection = function(rejection, extraContext) {
- return self.fatal(rejection, extraContext);
- };
- return this;
- };
- PromiseMonitor.prototype.createContext = function(at, parentContext) {
- var context = {
- parent: parentContext || executionContext[executionContext.length - 1],
- stack: void 0
- };
- error.captureStack(context, at.constructor);
- return context;
- };
- PromiseMonitor.prototype.addTrace = function(handler, extraContext) {
- var t, i;
- for(i = this._traces.length-1; i >= 0; --i) {
- t = this._traces[i];
- if(t.handler === handler) {
- break;
- }
- }
- if(i >= 0) {
- t.extraContext = extraContext;
- } else {
- this._traces.push({
- handler: handler,
- extraContext: extraContext
- });
- }
- this.logTraces();
- };
- PromiseMonitor.prototype.removeTrace = function(/*handler*/) {
- this.logTraces();
- };
- PromiseMonitor.prototype.fatal = function(handler, extraContext) {
- var err = new Error();
- err.stack = this._createLongTrace(handler.value, handler.context, extraContext).join('\n');
- setTimer(function() {
- throw err;
- }, 0);
- };
- PromiseMonitor.prototype.logTraces = function() {
- if(!this._traceTask) {
- this._traceTask = setTimer(this._doLogTraces, this.logDelay);
- }
- };
- PromiseMonitor.prototype._logTraces = function() {
- this._traceTask = void 0;
- this._traces = this._traces.filter(filterHandled);
- this._reporter.log(this.formatTraces(this._traces));
- };
- PromiseMonitor.prototype.formatTraces = function(traces) {
- return traces.map(function(t) {
- return this._createLongTrace(t.handler.value, t.handler.context, t.extraContext);
- }, this);
- };
- PromiseMonitor.prototype._createLongTrace = function(e, context, extraContext) {
- var trace = error.parse(e) || [String(e) + ' (WARNING: non-Error used)'];
- trace = filterFrames(this.stackFilter, trace, 0);
- this._appendContext(trace, context);
- this._appendContext(trace, extraContext);
- return this.filterDuplicateFrames ? this._removeDuplicates(trace) : trace;
- };
- PromiseMonitor.prototype._removeDuplicates = function(trace) {
- var seen = {};
- var sep = this.stackJumpSeparator;
- var count = 0;
- return trace.reduceRight(function(deduped, line, i) {
- if(i === 0) {
- deduped.unshift(line);
- } else if(line === sep) {
- if(count > 0) {
- deduped.unshift(line);
- count = 0;
- }
- } else if(!seen[line]) {
- seen[line] = true;
- deduped.unshift(line);
- ++count;
- }
- return deduped;
- }, []);
- };
- PromiseMonitor.prototype._appendContext = function(trace, context) {
- trace.push.apply(trace, this._createTrace(context));
- };
- PromiseMonitor.prototype._createTrace = function(traceChain) {
- var trace = [];
- var stack;
- while(traceChain) {
- stack = error.parse(traceChain);
- if (stack) {
- stack = filterFrames(this.stackFilter, stack);
- appendStack(trace, stack, this.stackJumpSeparator);
- }
- traceChain = traceChain.parent;
- }
- return trace;
- };
- function appendStack(trace, stack, separator) {
- if (stack.length > 1) {
- stack[0] = separator;
- trace.push.apply(trace, stack);
- }
- }
- function filterFrames(stackFilter, stack) {
- return stack.filter(function(frame) {
- return !stackFilter.test(frame);
- });
- }
- function filterHandled(t) {
- return !t.handler.handled;
- }
- return PromiseMonitor;
- });
- }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
|