【发布时间】:2015-09-29 07:07:39
【问题描述】:
我有这样的课:
import net from 'net';
import {EventEmitter} from 'events';
import Promise from 'bluebird';
class MyClass extends EventEmitter {
constructor(host = 'localhost', port = 10011) {
super(EventEmitter);
this.host = host;
this.port = port;
this.socket = null;
this.connect();
}
connect() {
this.socket = net.connect(this.port, this.host);
this.socket.on('connect', this.handle.bind(this));
}
handle(data) {
this.socket.on('data', data => {
});
}
send(data) {
this.socket.write(data);
}
}
如何将send 方法变成一个promise,它从套接字的data 事件中返回一个值?服务器只在数据发送到它时才返回数据,而不是很容易被抑制的连接消息。
我尝试过类似的方法:
handle(data) {
this.socket.on('data', data => {
return this.socket.resolve(data);
});
this.socket.on('error', this.socket.reject.bind(this));
}
send(data) {
return new Promise((resolve, reject) => {
this.socket.resolve = resolve;
this.socket.reject = reject;
this.socket.write(data);
});
}
显然这不起作用,因为resolve/reject 在并行链接和/或调用send 时会相互覆盖。
还有一个问题是同时调用send 两次,它会解决首先返回的响应。
我目前有一个使用队列和 defers 的实现,但感觉很乱,因为队列一直在被检查。
我希望能够做到以下几点:
let c = new MyClass('localhost', 10011);
c.send('foo').then(response => {
return c.send('bar', response.param);
//`response` should be the data returned from `this.socket.on('data')`.
}).then(response => {
console.log(response);
}).catch(error => console.log(error));
补充一点,我对接收到的数据没有任何控制权,这意味着它不能在流之外进行修改。
编辑:所以这似乎是不可能的,因为 TCP 没有请求-响应流。如何仍然使用 Promise 来实现这一点,但使用单次执行(一次一个请求)的 Promise 链或队列。
【问题讨论】:
-
你的意思是像双向聊天?发送一条消息,然后等到收到一条消息,就这样?
-
@thefourtheye 差不多,除了我可能需要并行调用
send并且承诺应该根据发送的内容返回正确的响应。虽然所有接收到的数据都来自一个流,所以它并不完全可追溯。 -
我猜这里...你能不能用
.add()方法在socket中设置某种观察者对象,然后从send()调用this.socket.observer.add({ reject: reject, resolve: resolve };? -
你的意思是像Q-Connection?
-
在您描述的方法(您尝试过的方法)中,链接时覆盖不是问题,因为您只在
then处理程序内第二次调用send(即,在第一个承诺已解决)。关于并行sends,无论语言/代码结构如何,这是不可能的,因为问题出在协议定义中。如果你想要一个串行的请求/响应通信协议(即没有相关的消息 id),你必须遵守规则并在发送下一个请求之前等待响应。
标签: javascript node.js tcp promise ecmascript-6