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