最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to Promisify node.js net.connect (with bluebird)? - Stack Overflow

programmeradmin6浏览0评论

I'd like a Promise version of node.js function net.connect. The Promise should be resolved with the socket if connection is successful, rejected with error if there's a connection error and preferably it should be cancellable as well, where cancellation would stop the connection attempt.

I did a quick try myself, but have not implemented cancellation 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, this seems to be awfully plex for such a simple thing. Is there a better way? Has somebody already done this?

I'd like a Promise version of node.js function net.connect. The Promise should be resolved with the socket if connection is successful, rejected with error if there's a connection error and preferably it should be cancellable as well, where cancellation would stop the connection attempt.

I did a quick try myself, but have not implemented cancellation 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, this seems to be awfully plex for such a simple thing. Is there a better way? Has somebody already done this?

Share Improve this question edited Dec 25, 2014 at 11:15 Benjamin Gruenbaum 277k89 gold badges520 silver badges517 bronze badges asked Oct 19, 2014 at 7:02 NakedibleNakedible 4,1687 gold badges36 silver badges42 bronze badges 10
  • 1 I would not remend using a promise for this. – Benjamin Gruenbaum Commented Oct 19, 2014 at 7:04
  • Agree with @BenjaminGruenbaum, you can use event handling anyway here, why you need promises? Just write connect, and catch events as you do it inside of promise. – Zav Commented Oct 19, 2014 at 7:06
  • 1 I want to write .then(connect()).then(doThing()).then(close()) style sequences. This seems to be standard practice for DB access where db.connect is promisified - this is shown even in bluebird examples. Why is net.connect so different? – Nakedible Commented Oct 19, 2014 at 7:10
  • May be i'm wrong, but all this .then() methods will call simultaneously. – Zav Commented Oct 19, 2014 at 7:13
  • 1 I'll post an answer next week if you're still stuck as well as why Bluebird doesn't and won't support promo sifting event emitters automatically. – Benjamin Gruenbaum Commented Oct 19, 2014 at 16:40
 |  Show 5 more ments

3 Answers 3

Reset to default 2

All in all if you look at it directly - EventEmitters ings are a very plicated abstraction.

Promises represent sequencing operations - think of them as the assignment operator or a semicolon. Code in regular sync programming looks something like:

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

Things run one after the other:

  1. Enter the try block
  2. Run foo with argument bar
  3. Log the value unless there was an error
  4. If there was an error, handle it.

It's like a long single chain of operations. A promise is exactly like this:

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

A promise is a chain. You can create several such chains, which is similar to other forms of concurrency (like threads) which represent executing a sequence of actions. It looks something like the following:

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

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

On the other hand - an event emitter has no guarantees about the name or type of events it fires, the node EventEmitter has some cool features baked in (like stack traces and error events) but there is a much weaker convention than there is with promises - different event emitters fire different events, an event emitter can do something like this:

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

              --Handler 2                                         --Handler 2

It is not a single chain - so while there have been several attempts and discussions about this - no generic way to represent promises from event emitters exists - they're simply too different in the event handling and the event name.

On the other hand - pg.connect takes a node style err-callback. So it's easy to promisify, those are very well specified and abide to a contract.

What you have is fine, and you can generalize it to an event emitter with two events. Remember you write this sort of boilerplate once and then use it all over your code :)

You can remove the two removeListener() lines. Promises can only be resolved or rejected once so you don't have to worry about your events getting called again. The promise won't change it's state once it is fullfilled.

And, I think you have a couple issues to fix:

  1. var connect_args = arguments probably won't work since arguments is a funky type of temporal object. The usual work-around is to make a copy of it's contents: var connect_args = [].slice.call(arguments);.

  2. In this line, net.connect.apply(this, connect_args);, I don't think this will be the right value because you're inside the promise callback at that point (perhaps it doesn't matter in this particular case). It would likely be more technically correct to use net.connect.apply(net, connect_args); which will more directly simulate calling net.connect(args).

As for the wisdom of using promises for this at all, it looks like you have a couple of opinions on the matter in the ments.

Other than removing the removeListener() lines of code, I don't think there's really much of a way to simplify this. You're creating a promise to respond to two different custom conditions so you have to write the code to detect those two conditions. No way around that.

P.S. If you don't remove the removeListener() lines of code, you may hav an error because you're setting up an event for 'connect', but doing a removeListener('connection). Also, I don't know why you're passing a function to removeListener() because it's not the same function reference you used when the event handler was established.

The solutions I've e up with match what you've got nearly identically:

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 occasionally when things get more unpleasant:

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 filed an issue about this (asking for documentation) here but got redirected to your question.

I've e to the conclusion that the current intersection of promises and event emitters is just ugly and I have to live with it. I've not e across any better suggestions than what we've independently invented, so if you do, please share.

发布评论

评论列表(0)

  1. 暂无评论