285 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			285 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @license
							 | 
						||
| 
								 | 
							
								 * Copyright Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Use of this source code is governed by an MIT-style license that can be
							 | 
						||
| 
								 | 
							
								 * found in the LICENSE file at https://angular.io/license
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								(function(_global) {
							 | 
						||
| 
								 | 
							
								  var allTasks = _global['__zone_symbol__performance_tasks'];
							 | 
						||
| 
								 | 
							
								  if (!allTasks) {
							 | 
						||
| 
								 | 
							
								    allTasks = _global['__zone_symbol__performance_tasks'] = [];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var mark = _global['__zone_symbol__mark'] = function(name) {
							 | 
						||
| 
								 | 
							
								    performance && performance['mark'] && performance['mark'](name);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var measure = _global['__zone_symbol__measure'] = function(name, label) {
							 | 
						||
| 
								 | 
							
								    performance && performance['measure'] && performance['measure'](name, label);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var getEntries = _global['__zone_symbol__getEntries'] = function() {
							 | 
						||
| 
								 | 
							
								    performance && performance['getEntries'] && performance['getEntries']();
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var getEntriesByName = _global['__zone_symbol__getEntriesByName'] = function(name) {
							 | 
						||
| 
								 | 
							
								    return performance && performance['getEntriesByName'] && performance['getEntriesByName'](name);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var clearMarks = _global['__zone_symbol__clearMarks'] = function(name) {
							 | 
						||
| 
								 | 
							
								    return performance && performance['clearMarks'] && performance['clearMarks'](name);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var clearMeasures = _global['__zone_symbol__clearMeasures'] = function(name) {
							 | 
						||
| 
								 | 
							
								    return performance && performance['clearMeasures'] && performance['clearMeasures'](name);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var averageMeasures = _global['__zone_symbol__averageMeasures'] = function(name, times) {
							 | 
						||
| 
								 | 
							
								    var sum = _global['__zone_symbol__getEntriesByName'](name)
							 | 
						||
| 
								 | 
							
								                  .filter(function(m) { return m.entryType === 'measure'; })
							 | 
						||
| 
								 | 
							
								                  .map(function(m) { return m.duration })
							 | 
						||
| 
								 | 
							
								                  .reduce(function(sum, d) { return sum + d; });
							 | 
						||
| 
								 | 
							
								    return sum / times;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var serialPromise = _global['__zone_symbol__serialPromise'] =
							 | 
						||
| 
								 | 
							
								      function(promiseFactories) {
							 | 
						||
| 
								 | 
							
								    let lastPromise;
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < promiseFactories.length; i++) {
							 | 
						||
| 
								 | 
							
								      var promiseFactory = promiseFactories[i];
							 | 
						||
| 
								 | 
							
								      if (!lastPromise) {
							 | 
						||
| 
								 | 
							
								        lastPromise = promiseFactory.factory(promiseFactory.context).then(function(value) {
							 | 
						||
| 
								 | 
							
								          return {value, idx: 0};
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        lastPromise = lastPromise.then(function(ctx) {
							 | 
						||
| 
								 | 
							
								          var idx = ctx.idx + 1;
							 | 
						||
| 
								 | 
							
								          var promiseFactory = promiseFactories[idx];
							 | 
						||
| 
								 | 
							
								          return promiseFactory.factory(promiseFactory.context).then(function(value) {
							 | 
						||
| 
								 | 
							
								            return {value, idx};
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return lastPromise;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var callbackContext = _global['__zone_symbol__callbackContext'] = {};
							 | 
						||
| 
								 | 
							
								  var zone = _global['__zone_symbol__callbackZone'] = Zone.current.fork({
							 | 
						||
| 
								 | 
							
								    name: 'callback',
							 | 
						||
| 
								 | 
							
								    onScheduleTask: function(delegate, curr, target, task) {
							 | 
						||
| 
								 | 
							
								      delegate.scheduleTask(target, task);
							 | 
						||
| 
								 | 
							
								      if (task.type === callbackContext.type &&
							 | 
						||
| 
								 | 
							
								          task.source.indexOf(callbackContext.source) !== -1) {
							 | 
						||
| 
								 | 
							
								        if (task.type === 'macroTask' || task.type === 'eventTask') {
							 | 
						||
| 
								 | 
							
								          var invoke = task.invoke;
							 | 
						||
| 
								 | 
							
								          task.invoke = function() {
							 | 
						||
| 
								 | 
							
								            mark(callbackContext.measureName);
							 | 
						||
| 
								 | 
							
								            var result = invoke.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								            measure(callbackContext.measureName, callbackContext.measureName);
							 | 
						||
| 
								 | 
							
								            return result;
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								        } else if (task.type === 'microTask') {
							 | 
						||
| 
								 | 
							
								          var callback = task.callback;
							 | 
						||
| 
								 | 
							
								          task.callback = function() {
							 | 
						||
| 
								 | 
							
								            mark(callbackContext.measureName);
							 | 
						||
| 
								 | 
							
								            var result = callback.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								            measure(callbackContext.measureName, callbackContext.measureName);
							 | 
						||
| 
								 | 
							
								            return result;
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return task;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var runAsync = _global['__zone_symbol__runAsync'] = function(testFn, times, _delay) {
							 | 
						||
| 
								 | 
							
								    var delay = _delay | 100;
							 | 
						||
| 
								 | 
							
								    const fnPromise = function() {
							 | 
						||
| 
								 | 
							
								      return new Promise(function(res, rej) {
							 | 
						||
| 
								 | 
							
								        // run test with a setTimeout
							 | 
						||
| 
								 | 
							
								        // several times to decrease measurement error
							 | 
						||
| 
								 | 
							
								        setTimeout(function() { testFn().then(function() { res(); }); }, delay);
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    var promiseFactories = [];
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < times; i++) {
							 | 
						||
| 
								 | 
							
								      promiseFactories.push({factory: fnPromise, context: {}});
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return serialPromise(promiseFactories);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var getNativeMethodName = function(nativeWithSymbol) {
							 | 
						||
| 
								 | 
							
								    return nativeWithSymbol.replace('__zone_symbol__', 'native_');
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function testAddRemove(api, count) {
							 | 
						||
| 
								 | 
							
								    var timerId = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var name = api.method;
							 | 
						||
| 
								 | 
							
								    mark(name);
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								      timerId.push(api.run());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    measure(name, name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (api.supportClear) {
							 | 
						||
| 
								 | 
							
								      var clearName = api.clearMethod;
							 | 
						||
| 
								 | 
							
								      mark(clearName);
							 | 
						||
| 
								 | 
							
								      for (var i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								        api.runClear(timerId[i]);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      measure(clearName, clearName);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    timerId = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var nativeName = getNativeMethodName(api.nativeMethod);
							 | 
						||
| 
								 | 
							
								    mark(nativeName);
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								      timerId.push(api.nativeRun());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    measure(nativeName, nativeName);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (api.supportClear) {
							 | 
						||
| 
								 | 
							
								      var nativeClearName = getNativeMethodName(api.nativeClearMethod);
							 | 
						||
| 
								 | 
							
								      mark(nativeClearName);
							 | 
						||
| 
								 | 
							
								      for (var i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								        api.nativeRunClear(timerId[i]);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      measure(nativeClearName, nativeClearName);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return Promise.resolve(1);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function testCallback(api, count) {
							 | 
						||
| 
								 | 
							
								    var promises = [Promise.resolve(1)];
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								      var r = api.run();
							 | 
						||
| 
								 | 
							
								      if (api.isAsync) {
							 | 
						||
| 
								 | 
							
								        promises.push(r);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								      var r = api.nativeRun();
							 | 
						||
| 
								 | 
							
								      if (api.isAsync) {
							 | 
						||
| 
								 | 
							
								        promises.push(r);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return Promise.all(promises);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function measureCallback(api, ops) {
							 | 
						||
| 
								 | 
							
								    var times = ops.times;
							 | 
						||
| 
								 | 
							
								    var displayText = ops.displayText;
							 | 
						||
| 
								 | 
							
								    var rawData = ops.rawData;
							 | 
						||
| 
								 | 
							
								    var summary = ops.summary;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var name = api.method;
							 | 
						||
| 
								 | 
							
								    var nativeName = getNativeMethodName(api.nativeMethod);
							 | 
						||
| 
								 | 
							
								    var measure = averageMeasures(name, times);
							 | 
						||
| 
								 | 
							
								    var nativeMeasure = averageMeasures(nativeName, times);
							 | 
						||
| 
								 | 
							
								    displayText += `- ${name} costs ${measure} ms\n`;
							 | 
						||
| 
								 | 
							
								    displayText += `- ${nativeName} costs ${nativeMeasure} ms\n`;
							 | 
						||
| 
								 | 
							
								    var absolute = Math.floor(1000 * (measure - nativeMeasure)) / 1000;
							 | 
						||
| 
								 | 
							
								    displayText += `# ${name} is ${absolute}ms slower than ${nativeName}\n`;
							 | 
						||
| 
								 | 
							
								    rawData[name + '_measure'] = measure;
							 | 
						||
| 
								 | 
							
								    rawData[nativeName + '_measure'] = nativeMeasure;
							 | 
						||
| 
								 | 
							
								    summary[name] = absolute + 'ms';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function measureAddRemove(api, ops) {
							 | 
						||
| 
								 | 
							
								    var times = ops.times;
							 | 
						||
| 
								 | 
							
								    var displayText = ops.displayText;
							 | 
						||
| 
								 | 
							
								    var rawData = ops.rawData;
							 | 
						||
| 
								 | 
							
								    var summary = ops.summary;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var name = api.method;
							 | 
						||
| 
								 | 
							
								    var nativeName = getNativeMethodName(api.nativeMethod);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var measure = averageMeasures(name, times);
							 | 
						||
| 
								 | 
							
								    var nativeMeasure = averageMeasures(nativeName, times);
							 | 
						||
| 
								 | 
							
								    displayText += `- ${name} costs ${measure} ms\n`;
							 | 
						||
| 
								 | 
							
								    displayText += `- ${nativeName} costs ${nativeMeasure} ms\n`;
							 | 
						||
| 
								 | 
							
								    var percent = Math.floor(100 * (measure - nativeMeasure) / nativeMeasure);
							 | 
						||
| 
								 | 
							
								    displayText += `# ${name} is ${percent}% slower than ${nativeName}\n`;
							 | 
						||
| 
								 | 
							
								    rawData[name + '_measure'] = measure;
							 | 
						||
| 
								 | 
							
								    rawData[nativeName + '_measure'] = nativeMeasure;
							 | 
						||
| 
								 | 
							
								    summary[name] = percent + '%';
							 | 
						||
| 
								 | 
							
								    if (api.supportClear) {
							 | 
						||
| 
								 | 
							
								      var clearName = api.clearMethod;
							 | 
						||
| 
								 | 
							
								      var nativeClearName = getNativeMethodName(api.nativeClearMethod);
							 | 
						||
| 
								 | 
							
								      var clearMeasure = averageMeasures(clearName, times);
							 | 
						||
| 
								 | 
							
								      var nativeClearMeasure = averageMeasures(nativeClearName, times);
							 | 
						||
| 
								 | 
							
								      var clearPercent = Math.floor(100 * (clearMeasure - nativeClearMeasure) / nativeClearMeasure);
							 | 
						||
| 
								 | 
							
								      displayText += `- ${clearName} costs ${clearMeasure} ms\n`;
							 | 
						||
| 
								 | 
							
								      displayText += `- ${nativeClearName} costs ${nativeClearMeasure} ms\n`;
							 | 
						||
| 
								 | 
							
								      displayText += `# ${clearName} is ${clearPercent}% slower than ${nativeClearName}\n`;
							 | 
						||
| 
								 | 
							
								      rawData[clearName + '_measure'] = clearMeasure;
							 | 
						||
| 
								 | 
							
								      rawData[nativeClearName + '_measure'] = nativeClearMeasure;
							 | 
						||
| 
								 | 
							
								      summary[clearName] = clearPercent + '%';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var testRunner = _global['__zone_symbol__testRunner'] = function(testTarget) {
							 | 
						||
| 
								 | 
							
								    var title = testTarget.title;
							 | 
						||
| 
								 | 
							
								    var apis = testTarget.apis;
							 | 
						||
| 
								 | 
							
								    var methods = apis.reduce(function(acc, api) {
							 | 
						||
| 
								 | 
							
								      return acc.concat([
							 | 
						||
| 
								 | 
							
								        api.method, api.nativeMethod
							 | 
						||
| 
								 | 
							
								      ].concat(api.supportClear ? [api.clearMethod, api.nativeClearMethod] : [])
							 | 
						||
| 
								 | 
							
								                            .concat[api.method + '_callback', api.nativeMethod + '_callback']);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    }, []);
							 | 
						||
| 
								 | 
							
								    var times = testTarget.times;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    allTasks.push({
							 | 
						||
| 
								 | 
							
								      title: title,
							 | 
						||
| 
								 | 
							
								      cleanFn: function() {
							 | 
						||
| 
								 | 
							
								        methods.forEach(function(m) {
							 | 
						||
| 
								 | 
							
								          clearMarks(m);
							 | 
						||
| 
								 | 
							
								          clearMeasures(m);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      },
							 | 
						||
| 
								 | 
							
								      before: function() { testTarget.before && testTarget.before(); },
							 | 
						||
| 
								 | 
							
								      after: function() { testTarget.after && testTarget.after(); },
							 | 
						||
| 
								 | 
							
								      testFn: function() {
							 | 
						||
| 
								 | 
							
								        var count = typeof testTarget.count === 'number' ? testTarget.count : 10000;
							 | 
						||
| 
								 | 
							
								        var times = typeof testTarget.times === 'number' ? testTarget.times : 5;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var testFunction = function() {
							 | 
						||
| 
								 | 
							
								          var promises = [];
							 | 
						||
| 
								 | 
							
								          apis.forEach(function(api) {
							 | 
						||
| 
								 | 
							
								            if (api.isCallback) {
							 | 
						||
| 
								 | 
							
								              var r = testCallback(api, count / 100);
							 | 
						||
| 
								 | 
							
								              promises.push(api.isAsync ? r : Promise.resolve(1));
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								              var r = testAddRemove(api, count);
							 | 
						||
| 
								 | 
							
								              promises.push[api.isAsync ? r : Promise.resolve(1)];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								          return Promise.all(promises);
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return runAsync(testFunction, times).then(function() {
							 | 
						||
| 
								 | 
							
								          var displayText = `running ${count} times\n`;
							 | 
						||
| 
								 | 
							
								          var rawData = {};
							 | 
						||
| 
								 | 
							
								          var summary = {};
							 | 
						||
| 
								 | 
							
								          apis.forEach(function(api) {
							 | 
						||
| 
								 | 
							
								            if (api.isCallback) {
							 | 
						||
| 
								 | 
							
								              measureCallback(api, {times, displayText, rawData, summary});
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								              measureAddRemove(api, {times, displayText, rawData, summary});
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								          return Promise.resolve({displayText: displayText, rawData: rawData, summary: summary});
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}(typeof window === 'undefined' ? global : window));
							 |