I'm trying to create a module/class in node.js to measure asynchronous execution time but do not understand whats wrong with it. I created the following class "Measure.js"
var Measure = module.exports = function(param_timeout, param_cb) {
this.timeout = param_timeout;
this.cb = param_cb;
}
Measure.prototype = {
startDate: "0",
timeout:"0",
cb:null,
start : function() {
this.startDate = new Date();
console.log('started');
},
stop : function() {
var stopDate = new Date();
this.cb(null,(stopDate-this.startDate));
}
}
I use it with the following code:
var Measure = require('./Measure.js');
measure1 = new Measure(100,function(err,result){console.log('result: ' + result)});
measure1.start();
//do something
measure1.stop();
and it works just fine. However, if I try this:
var Measure = require('./Measure.js');
measure1 = new Measure(100,function(err,result){console.log('result: ' + result)});
measure1.start();
//do something
setTimeout(measure1.stop,100);
it doesn't work and throws a TypeError:
TypeError: Object #<Object> has no method 'cb'
Whats wrong with my code?
When you directly call object's method, this
inside the method referred to your object, but when you try to use it as argument, this
will referred to global object ( global
or window
).
In your case better to replace
setTimeout(measure1.stop,100);
with
setTimeout(function() { measure1.stop(); }, 100);
More about this
behavior: http://bonsaiden.github.com/JavaScript-Garden/#function.this
The dreaded timeout-switch-context bug strikes again! You see what you see because this
object in function called by setTimeout is not measure1
- it's global
(= window
, when this script is executed in browser). Quoting the MDN :
Code executed by
setTimeout()
is run in a separate execution context to the function from which it was called. As a consequence, thethis
keyword for the called function will be set to thewindow
(orglobal
) object, it will not be the same as thethis
value for the function that calledsetTimeout
.
It's quite easy to check, by the way:
stop: function() {
var stopDate = new Date();
if (! this.cb) {
console.log(this);
} // *Window*/_display...
}
... and to fix as well:
setTimeout(function() {
measure1.stop();
}, 100);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.