> It’s unclear why Express.js chose not to use a constant time data structure like a map to store its handlers. Its actually quite clear - most routes are defined by a regex rather than a string, so there is no built-in structure (if there's a way at all) to do O(1) lookups in the routing table. A router that only allowed string route definitions would be faster but far less useful. I can't explain away the recursion…
Node.js in Flame Graphs
81–90 of 259 posts
Re: Node.js in Flame Graphs
#82Earlier quoted context omitted.
Oh, right. My CS has gotten fuzzy - the tree gets enormous, but the runtime stays is O(n) on input length. Thanks for the explanation.
The automaton isn't even that big, really. The number of NFA states is roughly proportional to the total number of characters in the regular expressions involved, and NFA to DFA conversion usually expands the automaton only be a factor of two or three. Although the subset construction in theory worst-case exponential, that situation never occurs in practice.
I suspect this is a slight overestimate, but the point stands - non-trivial apps could quickly build very large state graphs.
Re: Node.js in Flame Graphs
#83If I had to pick one line to highlight (not to criticize, but was a wise lesson worth sharing) it would be this one: "First, we need to fully understand our dependencies before putting them into production."
Re: Node.js in Flame Graphs
#84Earlier quoted context omitted.
A lot of people here are right, the right way is with an NFA. I just want to add that the solution is not even hard, you can do it with string concatenation and capture groups using regexps. Regexps are NFAs, and are highly optimized C code in just about every JS engine. If I have the routes /foo/bar and /foo/bar/(\d+) I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) I'm not at all surprised, the qualit…
> I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) And how would you know which one got matched? The regex match isn't going to tell you that. Also, it needs to recognize if multiple were matched, which is definitely not going to be done by the built-in regex matcher. It's certainly possible, but pretending it's trivial isn't helping, either.
You could write a simple router based on this in < 50 lines of JS. I'd do it now, but I have work to do.
Re: Node.js in Flame Graphs
#85Earlier quoted context omitted.
A lot of people here are right, the right way is with an NFA. I just want to add that the solution is not even hard, you can do it with string concatenation and capture groups using regexps. Regexps are NFAs, and are highly optimized C code in just about every JS engine. If I have the routes /foo/bar and /foo/bar/(\d+) I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) I'm not at all surprised, the qualit…
> I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) And how would you know which one got matched? The regex match isn't going to tell you that. Also, it needs to recognize if multiple were matched, which is definitely not going to be done by the built-in regex matcher. It's certainly possible, but pretending it's trivial isn't helping, either.
>>> import re
>>> route = re.compile(r'(?P^/foo/bar$)|(?P^/foo/bar/\d+$)')
>>> route.match('/foo/bar').groupdict()
{'fb': '/foo/bar', 'fbd': None}
>>> route.match('/foo/bar/1').groupdict()
{'fb': None, 'fbd': '/foo/bar/1'}
If the fb group is set, act on the first route. If the fbd group is set, act on the second.Re: Node.js in Flame Graphs
#86Earlier quoted context omitted.
A lot of people here are right, the right way is with an NFA. I just want to add that the solution is not even hard, you can do it with string concatenation and capture groups using regexps. Regexps are NFAs, and are highly optimized C code in just about every JS engine. If I have the routes /foo/bar and /foo/bar/(\d+) I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) I'm not at all surprised, the qualit…
> I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) And how would you know which one got matched? The regex match isn't going to tell you that. Also, it needs to recognize if multiple were matched, which is definitely not going to be done by the built-in regex matcher. It's certainly possible, but pretending it's trivial isn't helping, either.
Re: Node.js in Flame Graphs
#87> This turned out be caused by a periodic (10/hour) function in our code. The main purpose of this was to refresh our route handlers from an external source. This was implemented by deleting old handlers and adding new ones to the array. Unfortunately, it was also inadvertently adding a static route handler with the same path each time it ran. I don't understand the need of refreshing route handlers. Could someone ex…
Re: Node.js in Flame Graphs
#88Re: Node.js in Flame Graphs
#89Earlier quoted context omitted.
Are there some salient points that can be summarized here? That's an hour-and-twenty-minute podcast episode.
The motivation part starts around 8:30. It's hard to claim complete objectivity when it comes to things like this but it sounds particularly unconvincing to me. Node.js' sweetspot is providing an easy route to server development for front-end developers and it seems this is roughly what happened. It's not a huge step for Netflix that already has an API approach that is very UI centric as outlined here http://techblog…
My preference for node is based primarily on its sane concurrency model. I basically use it as a handy scripting language for doing rapid prototyping of libuv programs. My on-paper plan is to fall back to libuv and C if I find myself really stuck for CPU, but this is something that's never actually happened to me. (I have had to abandon or modify libraries with performance pathologies, though)
There are other libraries with in other languages the same sane model but they tend to be ecosystems within the language community that aren't compatible with the rest of the language. Doing concurrency both correctly and performantly in Java, in particular, is a pain in the ass.
Re: Node.js in Flame Graphs
#90Earlier quoted context omitted.
A lot of people here are right, the right way is with an NFA. I just want to add that the solution is not even hard, you can do it with string concatenation and capture groups using regexps. Regexps are NFAs, and are highly optimized C code in just about every JS engine. If I have the routes /foo/bar and /foo/bar/(\d+) I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) I'm not at all surprised, the qualit…
> I can generate the regexp ((^\/foo\/bar$)|(^\/foo\/bar\/\d+$)) And how would you know which one got matched? The regex match isn't going to tell you that. Also, it needs to recognize if multiple were matched, which is definitely not going to be done by the built-in regex matcher. It's certainly possible, but pretending it's trivial isn't helping, either.
> /(^\/foo\/bar$)|(^\/foo\/bar\/\d+$)/.exec('/foo/bar')
[ '/foo/bar',
'/foo/bar',
undefined,
index: 0,
input: '/foo/bar' ]
> /(^\/foo\/bar$)|(^\/foo\/bar\/\d+$)/.exec('/foo/bar/3')
[ '/foo/bar/3',
undefined,
'/foo/bar/3',
index: 0,
input: '/foo/bar/3' ]
EDIT: Markdown differences.