The code sample is -
global.a = 'aaa';
const obj = {
a: 'a',
desc() {
console.log(this);
console.log(this.a);
}
}
setTimeout(obj.desc, 2000)
When I run this code in nodejs, I get the following output:
Timeout {
_called: true,
_idleTimeout: 2000,
_idlePrev: null,
_idleNext: null,
_idleStart: 79,
_onTimeout: [Function: desc],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(asyncId)]: 6,
[Symbol(triggerAsyncId)]: 1 }
undefined
But the same code, with global
changed to window
in Chrome/Firefox prints aaa
and the window
object, which is what this MDN doc says and which is what I expect.
I was under the impression that nodejs and Chrome both use Google's v8 JS engine to execute JavaScript. So why is the output different? Is there something more to this? I tried searching but couldn't find satisfactory answers.
Node version - v9.10.
Chrome's version - Version 70.0.3538.110
The setTimeout() executes the function passed in the first argument after the time specified in the second argument. The setTimeout function doesn't block other code and the rest of the code is executed and after a specified time the code inside setTimeout function is executed.
Assuming we're talking about browser-based JavaScript: No difference. setTimeout() simply omits the window. , which is implied. The effect they have is exactly the same.
The setTimeout function is used to call a function after the specified number of milliseconds. The delay of the called function begins after the remaining statements in the script have finished executing. The setTimeout function is found in the Timers module of Node. js.
setImmediate() vs process.setTimeout() is processed in the Check handlers phase, while process. nextTick() is processed at the starting of the event loop and between each phase of the event loop. On any given context process. nextTick() has higher priority over setImmediate() .
node.js has its own implentation of timers which is different from browser implementations (although they can generally be used in the same way). This isn't really documented, but when you use setTimeout
, it creates an instance of a Timer
class with the callback passed as an argument. This callback is assigned to a property of the Timer
instance which is used later:
This means that the this
context for timers in node.js incidentally gets set to the Timer instance itself. Browsers apparently do something different.
This is mostly a semantic issue in your original code: when you pass function properties from objects they lose their context. You could use .bind
to retain the context, or use another function to call desc
directly on obj
to retain the context.
setTimeout(obj.desc.bind(obj), 2000);
setTimeout(() => obj.desc(), 2000);
These two will log obj
and obj.a
in both node.js and browser environments.
To answer your question, we must consult the source code for timers, since NodeJS' setTimeout
and vanilla JS' setTimeout
are not the same thing.
If we look here, we will find the definition for setTimeout
. We must pay attention to what happens with the callback that is passed in:
What happens is it is passed into the Timeout
constructor:
const timeout = new Timeout(callback, after, args, false);
Ok, so what is the Timeout
class? We can find that here. Notice the line:
this._onTimeout = callback;
Ok, we stick the callback in an instance member, so I suspect that's how it is being called.
If we go back to the other source file and search for _onTimeout
, we will find this line:
timer._onTimeout();
So in this case, because of how the callback is being called, timer
is in fact what this
refers to (as you've noted by logging this
from the callback), and since the timer (or Timeout
instance) does not have any such property (a
), it logs undefined
.
In vanilla JS, it behaves differently, and this
refers to the window
in your case.
As you may know, you can resolve this inconsistency by simply binding the callback to obj
in setTimeout
like so:
setTimeout(obj.desc.bind(obj), 2000);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With