Skip to content

perf: memoise the Content-Type resolution in res.set, res.type and setCharset - #7481

Open
nigrosimone wants to merge 1 commit into
expressjs:masterfrom
nigrosimone:perf/memoise-content-type
Open

nigrosimone wants to merge 1 commit into
expressjs:masterfrom
nigrosimone:perf/memoise-content-type

Conversation

@nigrosimone

Copy link
Copy Markdown

A response sets one of a handful of content types, and each of them goes through the mime database (mime.contentType in res.set and res.type) and, for a string body, through content-type's parse and format (setCharset in res.send). Profiled under load with autocannon, that is about 1.9 us per res.json and 0.9 us per res.send of a string, the largest cost in Express's own code after the prototype switch in app.handle.

This memoises both by their input, in maps capped at 100 entries. Same output for the same input, nothing observable changes. setCharset on the json type goes from 470 ns to 11. The cache for setCharset is a map per charset: a key made by joining the two strings measured 240 ns, since the joined string is hashed again on every call.

Self time per request, node 26, before and after: res.json route, mime.contentType 400 ns, content-type parse 280-315, parseParameters 255-303, format 218-291, skipValue 270, setCharset 233, charset 218, after only setCharset at 11 ns; res.send("Hello World"), mime.contentType 264-330, charset 190-207, lookup 154-159, res.type 314-384, after res.type at 132-178.

This is the same memoisation I did in fulmine.js, an Express 5 replacement on uWebSockets.js that keeps the API, where mime.contentType measured 273 ns a response and 6 memoised. It applies here as it is, since res.set and res.send see the same handful of types.

@nigrosimone
nigrosimone marked this pull request as ready for review September 20, 2026 06:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants