I've built a simple script to detect if a port is opened/closed on my machine. I've successfully make it work using the old-fashion callback way, but can't make it work with Promise (async/await).
Any clue why the two scripts below are not working exactly the same? Using callbacks, it works neat. Using Promise (async/await) it crash by throwing an "uncaughtException" error.
✅ Using callbacks
const net = require('node:net')
/**
* Connect to port with callback
*/
function connectToPort(port, callback) {
const client = net.connect(port, 'localhost', function () {
callback(true)
})
client.on('error', function (err) {
callback(err)
})
}
/**
* Connect
*/
async function test(port) {
console.log(`Trying to connect to port "${port}"...`)
// Connect with callback
connectToPort(port, function (result) {
console.log({ port, open: result === true })
})
}
// Output:
// Trying to connect to port "4242"...
// { port: 4242, open: false }
test(4242)
❌ Using Promise (async/await)
const net = require('node:net')
/**
* Connect to port with Promise
*/
function asyncConnectToPort(port) {
return new Promise(function (resolve, reject) {
const client = net.connect(port, 'localhost', function () {
resolve(true)
})
client.on('error', function (err) {
reject(err)
})
})
}
/**
* Connect
*/
async function test(port) {
console.log(`Trying to connect to port "${port}"...`)
// Connect with promise
const result = await asyncConnectToPort(port)
console.log({ port, open: result === true })
}
// Output:
// Trying to connect to port "4242"...
// Error: connect ECONNREFUSED 127.0.0.1:4242
test(4242)
Both scripts look exactly the same to me. Apparently, the "error" event must be present to avoid Nodejs to throw an "uncaughtException". That "special" event is detected when using callback, but I suspect it's not with Promise. Could it be something behind the scene that differs when working with await/async script?
CodePudding user response:
An error event is raised in both your code examples.
In the Promise code that you wrote you pass that error event to reject()
.
When you call reject
you raise an exception.
Hence, you get an exception in your Promise based code but not in the other code. You added one!.
Handling it is a case of:
try {
const result = await asyncConnectToPort(port)
console.log({ port, open: result === true })
} catch (e) {
// do something with e here
}
However a Promise can only be settled once.
The code you've written will call resolve
when the callback to net.connect
runs and it will call reject
on an error event but these are not mutually exclusive.
It's possible for your code to end up calling both resolve
and reject
, and also for it to call reject
multiple times.