4 ms·
Do I understand this right -- global variables are shared across all requests in node.js? If so, that is an insane design.
by jessedhillon 15y ago
Do I understand this right -- global variables are shared across all requests in node.js?
If so, that is an insane design.
- tikhonj 15y agoIt's not really a fault of node so much as a fault of JavaScript. While JavaScript is a beautiful and expressive language, it does have some annoying pitfalls; this is just one of them. Happily, this is all changing--in the long run, future versions of JavaScript should polish away these issues while maintaining the fundamentally sound core of the language. In the short run "use strict" lets you realize some of the upcoming improvements in otherwise legacy code.
- dbattaglia 15y agoNode is single-threaded, so yes they are shared. Requests are basically just multiplexed inside the same message loop. In my opinion it wouldn't be quite as scary if js didn't make it so damn simple to accidentally define a global variable (like in this instance, where it was never actually declared in globally-scoped code).
- bzbarsky 15y agoWhy does threading matter? You can have multiple JS global objects all running on the same thread. See any web browser.
- pbz 15y agoJS in browsers is not multi-threaded. There's only one JS thread where requests from async calls are queued: http://ejohn.org/blog/how-javascript-timers-work/ http://ejohn.org/blog/how-javascript-timers-work/ When dealing with true multi-threading you have all sorts of issues you need to worry about, like locking for writing, worrying about deadlocks, etc. that make coding much more difficult.
- bzbarsky 15y agoYes, I know JS in browsers is not multi-threaded. It runs multiple globals all on the same thread, as I said. Node is not multithreaded either; it could run a bunch of separate globals on the same thread as well, if it wanted to.
- allertonm 15y agoIndeed you can - but I suspect I know why Node has avoided this. If you did take advantage of the runtime's support for multiple global objects, what would those global objects correspond to? The most natural scope would be "user session" - but if you go that route, now you support stateful user sessions. And before you know it you have developers storing loads of user session state in the server's RAM and wondering why they keep running out - and lose the ability to easily fail over to another server process. So I imagine Node's author decided it was better to just keep things simple and discourage use of globals.
- bzbarsky 15y ago"user session" is tough, indeed. But doing global per request would not be that complicated, if desired.
- dbattaglia 15y agoWell I don't think web browsers are really the same thing as server side code. Even individual pages in a browser are sandboxed from each other. Just like individual request/response cycles for a user session probably should be on the server (unless you go out of your way to break that, ie making some variable "static").
- bzbarsky 15y agoMy point was that nothing inherent to JS forces sharing of a single global object across everything you do. The embedding (Node in this case) fully controls the granularity of such sharing.
- fennecfoxen 15y agoGlobal variables are basically instance variables on the process itself. They're going to be shared across all requests in all environments that handle more than a single request per process. If they had different semantics, they wouldn't really be what normal people call "global variables", would they? So you just don't use them and everything's good. Which brings you to the real problem: JavaScript makes it distressingly easy to use a global variable where you meant to use a local one.
- bzbarsky 15y ago> Global variables are basically instance variables on the > process itself. Not in JS. See my response to ww520 below.
- fennecfoxen 15y agoAh, I see what you're talking about. Seems like jesseedhillon was expecting that Node works like a browser: there's a lot of backend code in another language that handles the HTTP request, and then forks it over to a little JavaScript, and each request gets a new global scope. It's not like that. There's a teeny bit of C-based backend code; it's the JavaScript part that controls alll the interesting stuff like opening sockets and parsing HTTP headers and the like to determine a request. In a single process, with a single global object, with lots of asynchronous I/O. Node is JavaScript as a first-class programming language, not subservient to the DOM.
- bzbarsky 15y agoThis has nothing to do with the DOM. There are existing server-side JS deployments that have no DOM, but do create separate globals per request. There is nothing other than a conscious design decision that forces the Node code that you write to run against the same global as the code that handles the I/O guts in Node... In particular, you could have the code that listens on the socket and chunks up the byte stream into HTTP requests running against one global while all further processing of those requests runs against a different global or set of globals. It's just that Node chose not to do that. But that's not an inherent limitation of either JS the language or the V8 implementation.
- ww520 15y agoWell, that's what global variable means, shared among all functions in the process. Since there's only one process to handle all requests, they can access the global variables. All languages used in web server that don't spawn a new process for each request have the same feature.
- bzbarsky 15y agoIn JS, "global variable" means "property of the global object". No reference to "process". It's trivial to have a single-process JS application with multiple JS global objects in it. Case in point: any web browser (and renderer processes don't change this: every iframe on a page has a separate global object). It's just that Node _chose_ to reuse the same global object for multiple requests instead of using a clean execution environment. I have to agree with jessedhillon: that sounds insane.
- jessedhillon 15y agoI have to amend my previous statement, these guys are right. I created this Python script here https://gist.github.com/1329943 https://gist.github.com/1329943 and ran it. If global context were not shared, then each request would receive a new random number, but they don't. Each request gets the same number. Even without doing this experiment, the result is obvious. There would have to be some meta process to start new interpreter processes here in order to prevent the same environment from being reused. Since that is not the case, because you have to invoke the python interpreter manually here, you cannot get multiple distinct results. (Theoretically, in this code, you could get two different responses if they both entered the `if ... is None` clause in send_head() before one of the requests could cause the global variable to be set.)
- bzbarsky 15y agoYou're running your whole server in python. So yes, there is only one process and its globals are very much global. Note that you are NOT writing some program that embeds the python interpreter and then runs it on python code of your choice. In the case of Node, it's embedding V8. It can in fact run JS code of its choice in an environment of its choice, set up new globals, etc.