Repository navigation
Promisify server.listen #21482
Copy link
Copy link
Closed
Labels
feature requestIssues requesting new Node.js features.Issues requesting new Node.js features.netIssues and PRs related to the net subsystem.Issues and PRs related to the net subsystem.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
Description
Problem:
const server = app.listen();
console.log(`Server listening on: ${server.address().port}`)can fail, as the server is created asynchronously and using the callback is not always practical/flexible
Proposal
either server.listenPromise(port), or even better, have server.listen(port) return a Promise if no callback is provided
Example
// ....
const start = async () => {
await config.load();
await DB.connect(dbOptions);
router(app);
app.use((err, req, res, next) => { // error handler
// ...
});
const server = http.createServer(app);
// proposal:
return server.listen(process.env.PORT || 3000); // if .listen would be a promise resolving to server
// or await server.listen(...); return server; else
// currently I have to do:
// return new Promise((res, rej) => server.listen(process.env.PORT || 3000, err => err ? rej(err) : res()));
// or using express's app.listen, which wraps createServer and listen:
// return new Promise((res, rej) => app.listen(process.env.PORT || 3000, function (err) {
// if (err) return rej(err);
// res(this) // this is node's http Server
// }));
// using util.promisify doesn't look much better:
// return promisify(server.listen).bind(server)(process.env.PORT || 3000);
// or
// return promisify(cb => server.listen(process.env.PORT || 3000, cb))();
};then using it somewhere else:
start()
.then(server => console.log(`Server listening on: ${server.address().port}`))
.catch(err => {
// ...
});Edit: I'll try to submit this request to express, and have a similar promise method near https://github.com/expressjs/express/blob/master/lib/application.js#L616-L619
Edit2: the discussion in expressjs/express#3675 has interesting details
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
feature requestIssues requesting new Node.js features.Issues requesting new Node.js features.netIssues and PRs related to the net subsystem.Issues and PRs related to the net subsystem.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
Activity
jsmrcaga commentedon Aug 31, 2018
From what i see here, there would never be a real
.catch, since thecallbackis being forwarded to theServer.on('listening'event (except for two edge cases, you would still needserver.on('error')). This tricks you into believing your callback is being called once theserver.listenfunction has executed properly.I can introduce a
Promisereturn and start a PR if you like (as well as forServer.prototype.closeandServer.prototype.getConnections), but I think this particular case needs more attention than a single promise return. 🤔If so, should the returned
Promisebe conditional on the presence of a callback ? This could lead to some confusion, but then you might argue that we need that for retrocomp. 😄jsmrcaga commentedon Sep 1, 2018
I have been checking and experimenting with promisifying
server.listen+server.closeandserver.getConnections. There are two options, the 'lie to the devs' and return aPromise.resolve()or a more real option that would wrap the "maybe" callback and return a Promise.I can launch the PR if anyone is willing to read it and @node/collaborators think this is a good idea
caub commentedon Sep 13, 2018
@jsmrcaga Sorry but I didn't really understand how what you proposed would look like
just adding here another concise way suggested by @bmeck a while ago
But I still think a shortcut for this would be handy
shellscape commentedon Oct 9, 2018
@caub please forgive the naiveté, but is that a new fancy syntax capability for
awaitor is that pseudo code?addaleax commentedon Oct 9, 2018
@shellscape It’s the (existing) ability of
awaitto handle any value after it that has a.then()method that behaves like thePromise.prototype.then()one. This might be a slightly better example:I’m not sure it’s the most readable style to use
awaitwith, though. 😄shellscape commentedon Oct 9, 2018
@addaleax thanks! just learned something 😀
MartinMuzatko commentedon Feb 15, 2019
@caub I was pretty surprised, that util.promisfy needed to
.bind()the scope :OOtherwise, I am fine with promisify and bind, it does look ugly but it is better than nothing 👍
axkibe commentedon Apr 2, 2019
For the record thats an example that works (within an async function). As @MartinMuzatko pointed out, you need bind(), which is not quite obvious.
I'd too prefer that listen() would return a Promise whenever there isn't a callback provided.
For example the mongodb driver does this in a very nice way, which makes using it in async flow controls easy and compact.
PS: It would be cool if this would work with all asynchronous Node.js core library functions. If there isn't a callback, return a promise...
strarsis commentedon Aug 30, 2019
@axkibe: Using your code,
listenis undefined though afterwards, I need a reference to it for callingcloseon app shutdown.stavalfi commentedon Dec 10, 2019
don't you need to unsubscribe from the 'error' when 'listening' is fired? and the opposite as well?
webarnes commentedon Jan 12, 2020
You can use the "once" helper from "events":
More lines but fewer characters than the above solution and no need to unsubscribe.
That said, I'd love to just write
const server = await app.listen();Edit: Use CJS instead of ESM.
ftzi commentedon May 8, 2020
How to use it? I really can't understand it.
Tried this without success, stays stuck on '0'.
jsmrcaga commentedon May 8, 2020
@SrBrahma I'm not sure your 'listening' event exists, I don't see it nor on the official docs Node 14.2 or the express v4 docs.
My advice is to:
if you wish to use async/await:
21 remaining items
tompahoward commentedon Feb 16, 2023
@silverwind the reason why it never rejects is that:
i.e. it's never registered for the 'error' event. 😬
jrichardsz commentedon Dec 12, 2023
habemus
const server = await app.listen();??mosoriorian commentedon Jan 25, 2024
Any news on this issue?
mpicardvolvo commentedon Feb 28, 2024
bump
drmaquino commentedon Feb 28, 2024
has anyone already sent a PR with the proposal..?
axkibe commentedon Feb 29, 2024
Instead of "bumping" which does nothing on github, I suggest if this is still an issue for you to create a new one. I'd have to investigate the current state of affairs on this, which I right now don't have the time/energy for.
Generally speaking tough, from my impression 5 years ago when this issue was made, the node team was rather distanced to Promises, reluctantly adding them, which made me go ehh.. you don't see this is the js future? .. this has definitely changed and they embrace promises nowadays, so another attempt might go better (in case this is still an issue, I dunno)
net: add experimental net/promises API
net: tie listen() signal to server lifetime, async-iterable Server
net: use throwIfAborted and improve server iteration example
net: add experimental net/promises API
net: add experimental net/promises API
net: add experimental net/promises API