Skip to content

Commit

Permalink
Optimize performance of call-stack getting
Browse files Browse the repository at this point in the history
call stack not actually needed at most cases, but got always
get(actually only first get) call stack from error is so slow operation, and may be moved on-demand getter

Please see this simple example and his performance:
https://gist.github.com/Gvozd/291e4f0adf247ff70ed72150059e4977
with node:
  before commit: 810-840ms
  now: 170-180ms
with babel-node(slowe because source-map converting stack):
  before commit: 2900-3100ms
  now: 190-230ms
  • Loading branch information
Gvozd committed Feb 26, 2017
1 parent c26a2dd commit 6b27ce4
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 13 deletions.
11 changes: 9 additions & 2 deletions lib/sinon/call.js
Expand Up @@ -174,10 +174,17 @@ var callProto = {
return callStr;
}
};
Object.defineProperty(callProto, "stack", {
enumerable: true,
configurable: true,
get: function () {
return this.errorWithCallStack && this.errorWithCallStack.stack || "";
}
});

callProto.invokeCallback = callProto.yield;

function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack) {
function createSpyCall(spy, thisValue, args, returnValue, exception, id, errorWithCallStack) {
if (typeof id !== "number") {
throw new TypeError("Call id is not a number");
}
Expand All @@ -188,7 +195,7 @@ function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack)
proxyCall.returnValue = returnValue;
proxyCall.exception = exception;
proxyCall.callId = id;
proxyCall.stack = stack;
proxyCall.errorWithCallStack = errorWithCallStack;

return proxyCall;
}
Expand Down
20 changes: 9 additions & 11 deletions lib/sinon/spy.js
Expand Up @@ -130,7 +130,7 @@ var spyApi = {
this.thisValues = [];
this.exceptions = [];
this.callIds = [];
this.stacks = [];
this.errorsWithCallStack = [];
if (this.fakes) {
this.fakes.forEach(function (fake) {
fake.reset();
Expand Down Expand Up @@ -203,15 +203,13 @@ var spyApi = {
push.call(this.exceptions, exception);
push.call(this.returnValues, returnValue);
var err = new ErrorConstructor();
var stack = err.stack;
if (!stack) {
// PhantomJS does not serialize the stack trace until the error has been thrown:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack
try {
throw err;
} catch (e) {/* empty */}
}
push.call(this.stacks, err.stack);
// 1. Please do not get stack at this point. It's may be so very slow, and not actually used
// 2. PhantomJS does not serialize the stack trace until the error has been thrown:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack
try {
throw err;
} catch (e) {/* empty */}
push.call(this.errorsWithCallStack, err);

// Make return value and exception available in the calls:
createCallProperties.call(this);
Expand All @@ -235,7 +233,7 @@ var spyApi = {

return spyCall(this, this.thisValues[i], this.args[i],
this.returnValues[i], this.exceptions[i],
this.callIds[i], this.stacks[i]);
this.callIds[i], this.errorsWithCallStack[i]);
},

getCalls: function () {
Expand Down

0 comments on commit 6b27ce4

Please sign in to comment.