如何Promisify node.js net.connect(与bluebird)?

时间:2014-10-19 07:02:18

标签: javascript node.js promise bluebird

我想要一个node.js函数net.connect的Promise版本。如果连接成功,则应使用套接字解析Promise,如果出现连接错误则拒绝错误,并且最好也应取消,取消将停止连接尝试。

我自己做了一个快速尝试,但还没有实现取消:

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);
        });
    });
}

然而,对于这么简单的事情来说,这似乎非常复杂。有没有更好的办法?有人已经这样做了吗?

3 个答案:

答案 0 :(得分:1)

您可以删除两条removeListener()行。承诺只能被解决或拒绝一次,因此您不必担心再次调用您的事件。承诺一旦满满就不会改变它的状态。

而且,我认为你有几个问题需要解决:

  1. var connect_args = arguments可能无效,因为arguments是一种时髦对象的时髦对象。通常的解决方法是复制它的内容:var connect_args = [].slice.call(arguments);

  2. 在这一行net.connect.apply(this, connect_args);中,我不认为this将是正确的值,因为你在那个点内的promise回调中(也许它无关紧要)这个特殊情况)。使用net.connect.apply(net, connect_args);可能更直接模拟调用net.connect(args)在技术上更正确。

  3. 至于对此使用承诺的智慧,看起来你在评论中对此事有一些意见。

    除了删除removeListener()行代码之外,我认为没有太多方法可以简化这一过程。您正在创建一个响应两种不同自定义条件的承诺,因此您必须编写代码来检测这两个条件。没办法。

    P.S。如果您不删除removeListener()行代码,则可能会出现错误,因为您为'connect'设置了一个事件,但执行了removeListener('connection)。另外,我不知道你为什么要将函数传递给removeListener(),因为它与你在建立事件处理程序时使用的函数引用不同。

答案 1 :(得分:1)

总而言之,如果你直接看它 - EventEmitters ings是一个非常复杂的抽象。

Promise代表排序操作 - 将它们视为赋值运算符或分号。常规同步编程中的代码类似于:

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

事情一个接一个地运行:

  
      
  1. 输入试用块
  2.   
  3. 使用参数foo
  4. 运行bar   
  5. 记录值,除非出现错误
  6.   
  7. 如果出现错误,请处理。
  8.   

它就像长单链的操作。承诺就是这样:

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

承诺是一个链条。您可以创建多个此类链,这类似于其他形式的并发(如线程),表示执行一系列操作。它看起来像下面这样:

  

-------------------------------- + - 成功------------ ------>

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

另一方面 - 事件发射器无法保证它触发的事件的名称或类型,节点EventEmitter有一些很酷的功能(如堆栈跟踪和error事件)但是有很多比承诺更弱的约定 - 不同的事件发射器触发不同的事件,事件发射器可以做这样的事情:

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

              --Handler 2                                         --Handler 2

这不是一个单一的链 - 所以虽然已经有过多次尝试和讨论 - 但没有通用方法来表示来自事件发射器的承诺 - 它们在事件处理和事件名称方面完全不同。

另一方面 - pg.connect采用节点样式的err-callback。所以它很容易被宣传,这些都是非常明确的,并且遵守合同。

你拥有的很好,你可以将它推广到一个有两个事件的事件发射器。记住你写一次样板一次,然后在你的代码中使用它:)

答案 2 :(得分:1)

我提出的解决方案与你几乎完全相同:

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

偶尔当事情变得更加不愉快时:

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)

我提出了一个问题(要求提供文件)here,但已被重定向到您的问题。

我得出结论,当前的承诺和事件发射器的交集只是丑陋而且我必须忍受它。我没有遇到任何比我们独立发明的更好的建议,所以如果你这样做,请分享。