Javascript -从可以返回Promise布尔值或布尔值的函数中过滤结果



我不知道以前是否有人遇到过这个问题。

在我有一个EventHandler之前,它看起来是这样的:

export interface EventHandler {
name: string;
canHandleEvent(event: EventEntity): boolean;
handleEvent(event: EventEntity): Promise<void>;
}

我的过滤函数将正常工作,我的测试也通过了-我使用

过滤事件:
messages.forEach(message => {
const event: EventEntity = JSON.parse(message.Body);
this.handlers
.filter(handler => handler.canHandleEvent(event)) // WORKED WELL
.forEach(handler => {
// LOGIC
});

目前,我们必须将canHandleEvent更改为Boolean或Promise。因为我们有一些承诺要解决,并确定事件是否可以处理。

export interface EventHandler {
// ...
canHandleEvent(event: EventEntity): boolean | Promise<boolean>;
}

因此,为了求解它,我使用了Promise.resolvePromise.all。没有运气:

messages.forEach(async message => {
const event: EventEntity = JSON.parse(message.Body);
const handlersResolved = await Promise.all(this.handlers);
handlersResolved
.filter(handler => handler.canHandleEvent(event))
.forEach(handler => {

现在,我的测试通过了承诺canHandleEvent,但它们失败了通过的事件,即boolean。它们是这样的:

class HandlerB implements EventHandler {
name = HandlerB.name;
numRuns = 0;
canHandleEvent(event: EventEntity): boolean {
console.log('event', event)
return event.eventType === EventType.ONE_EVENT || event.eventType === EventType.SECOND_EVENT;
}
async handleEvent(event: EventEntity): Promise<void> {
return new Promise(resolve => {
setTimeout(() => {
this.numRuns += 1;
resolve();
}, 25);
});
}
}

我的测试现在失败了,之前是通过的是:

it('Should process handlers that match, including canHandleEvent that returns Promise<boolean> TRUE', async () => {
setHandlers([handlerA, handlerB, handlerC]);
const event = await createEvent(EventType.SECOND_EVENT);
await sleep(1000);
expect(handlerA.numRuns, 'handleA').to.eql(0);
expect(handlerB.numRuns, 'handleB').to.eql(1);
expect(handlerC.numRuns, 'handleC').to.eql(1); // handlerC is Promise<boolean>, it works fine
expect(errorHandler.numRuns).to.eql(0);
handlerC.numRuns = 0;
});
it('Should allow handlers to pass even if one has an error', async () => {
setHandlers([handlerA, handlerB, errorHandler]);
const event = await createEvent(EventType.USER_REGISTRATION_STATUS);
await sleep(1000);
expect(handlerA.numRuns, 'handlerA').to.eql(1);
expect(handlerB.numRuns, 'handlerB').to.eql(1);
expect(errorHandler.numRuns, 'errorHandler').to.eql(1);
});

对于如何解决这个问题有什么想法吗?我试图确定是否承诺或布尔在.filter内部之前,但仍然没有运气:

this.handlers
.filter(async handler =>  {
if(typeof handler.canHandleEvent(event).then == 'function') {
const result = await Promise.resolve(handler.canHandleEvent(event))
console.log('IS PROMISE!!', result);
return result
}
console.log('IT IS NOT PROMISE', handler.canHandleEvent(event))
return handler.canHandleEvent(event)
})

目前,我们必须将canHandleEvent更改为Boolean或Promise…

要清楚,这是一个巨大的语义变化,将波及使用该方法的每一层代码。例如,你不能再直接使用filter了,任何使用它的同步函数现在都可能是异步的(并且从根本上说,"可能是异步的")。="asynchronous"。但如果一定要发生,那就一定要发生!: -)

您使用canHandleEvent的原始代码如下:

messages.forEach(message => {
const event: EventEntity = JSON.parse(message.Body);
this.handlers
.filter(handler => handler.canHandleEvent(event)) // WORKED WELL
.forEach(handler => {
// LOGIC
});
});

必须变成异步的,像这样:

// Handles things in parallel, not series
await/*or return*/ Promise.all(messages.map(message => {
const event: EventEntity = JSON.parse(message.Body);
return Promise.all(this.handlers.map(handler => async {
if (await handler.canHandleEvent(event)) {
// LOGIC
}
}));
}));

注意每一层是如何受到影响的。messages.forEach变成了通过messages.map构建一个承诺数组,并通过await等待它们(或者使用.then等,或者返回到调用函数)。对于每条消息,我们对处理程序做同样的事情,因为我们无法知道处理程序是否可以同步处理某些内容。(不需要Promise.resolve,Promise.all将为您处理。)

上面的代码假设所有这些都可以重叠(消息和消息的处理程序),而之前因为它们都是同步的,所以它们都是串联发生的(一个消息的所有相关处理程序,按顺序,然后是下一个消息的所有处理程序,等等)。如果你需要像这样串联,你可以使用for-ofloops:

// Handles things in series, not parallel
// (In an `async` function)
for (const message of messages) {
const event: EventEntity = JSON.parse(message.Body);
for (const handler of this.handlers) {
if (await handler.canHandleEvent(event)) {
// LOGIC
}
}
}

在这两种情况下,可以处理返回boolean的(同步)和返回promise的不同,但这会使代码复杂化。

要解决您的问题,我认为最简单的方法是首先用期望值填充数组,以便您可以正确过滤。

const transformedHandlers = await Promise.all(this.handlers.map(async handler => {
return {
...handler,
eventCanBeHandled: await handler.canHandleEvent(event)
}
}))

这将转换数组,使您有一个键,显示可以处理的处理程序。

要完成它,你可以像往常一样使用你的代码,但不是检查

canHandleEvent

使用const transformmedhandlers中引入的新字段

下面的是例子:

transformedHandlers
.filter(handler => handler.eventCanBeHandled)
.forEach(handler => {
// LOGIC
});

这应该足以让你的代码像以前一样工作。

对不起,我的英语不好。这不是我的母语

最新更新