我想要一个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);
});
});
}
然而,对于这么简单的事情来说,这似乎非常复杂。有没有更好的办法?有人已经这样做了吗?
答案 0 :(得分:1)
您可以删除两条removeListener()
行。承诺只能被解决或拒绝一次,因此您不必担心再次调用您的事件。承诺一旦满满就不会改变它的状态。
而且,我认为你有几个问题需要解决:
var connect_args = arguments
可能无效,因为arguments
是一种时髦对象的时髦对象。通常的解决方法是复制它的内容:var connect_args = [].slice.call(arguments);
。
在这一行net.connect.apply(this, connect_args);
中,我不认为this
将是正确的值,因为你在那个点内的promise回调中(也许它无关紧要)这个特殊情况)。使用net.connect.apply(net, connect_args);
可能更直接模拟调用net.connect(args)
在技术上更正确。
至于对此使用承诺的智慧,看起来你在评论中对此事有一些意见。
除了删除removeListener()
行代码之外,我认为没有太多方法可以简化这一过程。您正在创建一个响应两种不同自定义条件的承诺,因此您必须编写代码来检测这两个条件。没办法。
P.S。如果您不删除removeListener()
行代码,则可能会出现错误,因为您为'connect'
设置了一个事件,但执行了removeListener('connection
)。另外,我不知道你为什么要将函数传递给removeListener()
,因为它与你在建立事件处理程序时使用的函数引用不同。
答案 1 :(得分:1)
总而言之,如果你直接看它 - EventEmitters ings是一个非常复杂的抽象。
Promise代表排序操作 - 将它们视为赋值运算符或分号。常规同步编程中的代码类似于:
try{
var value = foo(bar);
log(value);
} catch(e){
// handle error
}
事情一个接一个地运行:
- 输入试用块
- 使用参数
运行foo
bar
- 记录值,除非出现错误
- 如果出现错误,请处理。
醇>
它就像长单链的操作。承诺就是这样:
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,但已被重定向到您的问题。
我得出结论,当前的承诺和事件发射器的交集只是丑陋而且我必须忍受它。我没有遇到任何比我们独立发明的更好的建议,所以如果你这样做,请分享。