Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express and calling response.json in a point free fashion doesn't work in Promise.then

Something greatly surprised me today. I came across a bunch of express route handlers basically look like this (there are more and real function calls, but for the sake of legibility:

app.get('/api/foo', (req, resp) => {
  Promise.resolve({one: 1})
    .then(data=>resp.json(data))
})

So I, as the clever javascript programmer, think I can step away from the anonymous function and just let the then function call resp.json directly:

app.get('/api/foo', (req, resp) => {
  Promise.resolve({one: 1})
    .then(resp.json)
})

But when I try that I never get a response and see this in the node console:

Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'app' of undefined

To my eyes .then(resp.json) and .then(data=>resp.json(data)) should be equivalent. It's a scope thing, to be sure, but I'd love an explanation and perhaps a workaround.

like image 851
Robert Moskal Avatar asked Jan 05 '23 23:01

Robert Moskal


2 Answers

That's because resp is an object with it's own properties, so more than likely the data that is used by the json function is contained within the resp object.

When you pass the function resp.json by itself to then, you aren't passing the resp object, or any of its information, along with it. In essence, the then call is just "borrowing" the function json from the resp object. Just the function body itself though, no scope or implicit values.

More than likely, the function body of json uses this somewhere, at which point you will be getting an invalid (probably global) object, instead of resp.

To remedy, you can do

   Promise.resolve({one: 1})
    .then(resp.json.bind(resp))
like image 149
aaronofleonard Avatar answered Jan 07 '23 13:01

aaronofleonard


They are not the same because of how the this operator works in javascript.

Basically, resp.json(data) calls the function with this===resp, while resp.json calls the function with this===global.

To fix it, pass the function with bound parameters .then(resp.json.bind(resp)) (or use the arrow function).

like image 25
tcooc Avatar answered Jan 07 '23 13:01

tcooc