使用BlueBird和amqplib的TypeScript。我读到的地方只有输家使用“推迟”,我不想成为输家(至少为此)。所以我开始尝试重写这个 - 没有用 - (仅仅是):
public Request<Rq extends IPublishable, Rs extends IPublishable>(request: Rq): { ackd: Promise<boolean>; response: Promise<Rs> } {
var ackdPromise: Promise<boolean>;
var responsePromise: Promise<Rs>;
var confirmPublish = Promise.promisify(this.ConfirmChannel.publish, this.ConfirmChannel);
var consumerTag = uuid.v4();
var responseQueue = Bus.rpcQueueBase + consumerTag;
var responseDeferred = Promise.defer<Rs>();
var handleResponse = (msg: IPublishedObj): void => {
//ack first
this.ConfirmChannel.ack(msg);
this.ConfirmChannel.cancel(consumerTag);
responseDeferred.resolve(Bus.FromSubscription(msg));
}
responsePromise = responseDeferred.promise;
ackdPromise = Promise.resolve(this.ConfirmChannel.assertQueue(responseQueue, { durable: false, exclusive: true, autoDelete: true }))
.then((okQueueReply) => Promise.resolve(this.ConfirmChannel.consume(responseQueue, handleResponse, { consumerTag: consumerTag })))
.then((okSubscribeReply) => Promise.resolve(this.ConfirmChannel.assertExchange(Bus.rpcExchange, 'direct', { durable: true, autoDelete: false })))
.then((okExchangeReply) => confirmPublish(Bus.rpcExchange, request.GetType(), Bus.ToBuffer(request), { type: request.GetType(), replyTo: responseQueue }))
.then(this.handleAck, this.handleNack)
.catch((failReason) => {
console.error(util.format('Error publishing: %s', failReason));
return false;
});
return { ackd: ackdPromise, response: responsePromise };
}
我已经转换了所有类似的方法,并在此处进行了几次运行,但是一直在做空。也许是因为我试图返回两个值(确认承诺和响应承诺),但实际上我认为它与尝试返回调用嵌入式处理程序的最终结果的承诺有关 - 而不使用延迟。
你能(请)做得更好(或者告诉我推迟还可以)?
答案 0 :(得分:1)
以下行接受回调并返回一个承诺:
.then((okQueueReply) => Promise.resolve(this.ConfirmChannel.consume(responseQueue, handleResponse, { consumerTag: consumerTag })))
相反,仅仅从它返回一个承诺就足够了,所以它变成了:
.then((okQueueReply) => Promise.resolve(this.ConfirmChannel.consume(responseQueue, { consumerTag: consumerTag })))
虽然我们在那里,但Promise.resolve在.then
处理程序中是多余的,因为它们已经同化了承诺。而且,使用okSubscribedReply
进行解析只有在有意义的情况下才有用,否则你知道事情没有问题,因为承诺并没有拒绝。因此,最好返回有意义的数据。
由于承诺链可以轻松分支,这将使您的代码类似于:
var queueSet = { durable: false, exclusive: true, autoDelete: true };
var tag = { consumerTag: consumerTag };
var channel = Promise.resolve(this.ConfirmChannel.assertQueue(responseQueue, queueSet))
.then((okQueueReply) => this.ConfirmChannel.consume(responseQueue, tag));
var responsePromise = channel.then((msg) => {
this.ConfirmChannel.ack(msg); // I don't like this, but ok.
this.ConfirmChannel.cancel(consumerTag);
return Bus.FromSubscription(msg);
});
因此,我们的responsePromise
执行相同的操作,但现在不需要延迟,因为对于我们的ackdPromise
,我们只需将其从频道链接即可。
var exchangeSet = { durable: true, autoDelete: false };
var ackdPromise = channel.then(() => this.ConfirmChannel.assertExchange(Bus.rpcExchange, 'direct', exchangeSet)).then(....);
由于您一直使用.ConfirmChannel
而不是直接this
,我们可以使用.bind
并执行以下操作:
var assertSettings = { durable: false, exclusive: true, autoDelete: true };
var p = Promise.bind(this.ConfirmChannel)
.then(() => this.assertQueue(responseQueue, assertSettings))
.then(() => this.consume(responseQueue, {consumerTag: consumerTag}));
var responsePromise = p.then((msg) => {
this.ack(msg);
this.cacnel(consumerTag);
return Bus.FromSubscription(msg);
});
var exSet = { durable: true, autoDelete: false };
var pubSet = { type: request.GetType(), replyTo: responseQueue };
var ackdPromise = p.then(() => assertExchange(Bus.rpcExchange, 'direct', exSet))
.then(() => confirmPublish(Bus.rpcExchange,
request.GetType(),
Bus.ToBuffer(request), pubSet))
.then(this.handleAck, this.handleNack)
.catch(function(err){
console.error(util.format('Error publishing: %s', failReason));
return false;
});
return { ackd: ackdPromise, response: responsePromise };