How to Promisify node.js net.connect (with blue bird)?

I need the Promise node.js function version net.connect

. The promise should be resolved using a socket if the connection is successful, rejected with an error if there is a connection error, and preferably should also be canceled if canceling stops the connection attempt.

I quickly tried, but haven't done undo yet:

function connectAsync() {
    var connect_args = arguments;
    return new Promise(function (resolve, reject) {
        var socket = net.connect.apply(this, connect_args);
        socket.once('connect', function () {
            socket.removeListener('error', reject);
            resolve(socket);
        });
        socket.once('error', function (err) {
            socket.removeListener('connection', resolve);
            reject(err);
        });
    });
}

      

However, it seems terribly complicated for such a simple thing. Is there a better way? Has anyone already done this?

+3


source to share


3 answers


You can delete two lines removeListener()

. Promises can only be resolved or rejected once, so you don't have to worry about your events being called again. A promise will not change its state once it is filled.

And I think you have a couple of problems to fix:

  • var connect_args = arguments

    probably won't work as it arguments

    is a funky type of temporary object. Bypass the usual way is to copy its contents: var connect_args = [].slice.call(arguments);

    .

  • On this line, net.connect.apply(this, connect_args);

    I don't think what this

    would be the correct value, because you are in the promise callback at this point (maybe it doesn't matter in this particular case) It would probably be more technically correct to use net.connect.apply(net, connect_args);

    that would simulate more directly challenge net.connect(args)

    .



As for the wisdom of using Promises to do this in general, it looks like you have several opinions on this in the comments.

Other than removing lines of code removeListener()

, I don't think there really is a way to simplify this. You are creating a promise to respond to two different custom conditions, so you need to write code to detect these two conditions. Nothing like this.

PS If you don't remove lines of code removeListener()

, you might have an error because you are setting up an event for 'connect'

, but do removeListener('connection

). Also, I don't know why you are passing the function in removeListener()

, because it is not the same function you were using when the event handler was installed.

+1


source


In general, if you look at it directly, EventEmitters are a very complex abstraction.

Promises represent sequencing operations - think of them as an assignment operator or semicolon. The code in regular synchronization programming looks something like this:

try{
    var value = foo(bar);
    log(value);
} catch(e){
    // handle error
}

      

Everything happens one by one:

  • Enter a try block
  • Run foo

    with an argumentbar

  • Write down the value if there was no error
  • If an error occurs, handle it.

It looks like a long chain of operations. The promise is this:

 fooAsync(bar).
 then(log).
 catch(function(){
      // handle error
 });

      



A promise is a chain. You can create multiple such chains, which are similar to other forms of concurrency (for example, threads), which represent the execution of a sequence of actions. It looks something like this:

-------------------------------- + - Success ------------ --- --->

                   --Error---->// might join up

      

On the other hand - the event emitter has no guarantees about the name or type of events it fires, the node EventEmitter has some interesting features baked into (like stack traces and events error

), but there is a much weaker convention than with promises - different event emitters fire different events, event emitter can do something like this:

----Foo fired-+-Handler 1    ---- Bar fired-+      ---- Baz Fired-+-Handler 1

              --Handler 2                                         --Handler 2

      

It is not one chain - so when there have been several attempts and discussions about it, there is no general way to represent promises from event emitters - they are simply too different in event handling and event name.

On the other hand - pg.connect

accepts an erroneous node style callback. So it is easy to clarify, they are very well specified and are in line with the contract.

You are doing well and you can generalize it to a 2 event source. Remember that you write this type of template once and then use it throughout your code :)

+1


source


The solutions I came across match what you have almost the same:

p = new Promise((resolve, reject) ->
    listener = (data) ->
        try
            check_data_format(data)
        catch err
            return reject(err)
        if is_right_data(data)
            return resolve()
    ee.on("stdout", listener)
)
return p

      

and sometimes when the situation gets more frustrating:

reject_f = null
resolve_f = null
p = new Promise((resolve, reject) ->
    reject_f = reject
    resolve_f = resolve
)
listener = (data) ->
    try
        check_data_format(data)
    catch err
        return reject(err)
    if is_right_data(data)
        return resolve()
ee.on("stdout", listener)

      

I wrote about it (asked for documentation) here , but redirected to your question.

I've come to the conclusion that the current intersection of promises and event emitters is just ugly and I need to live with it. I haven't come across any better suggestions than the one we invented ourselves, so if you do, please share it.

+1


source







All Articles