笑话:await vs setImmediate vs useFakeTimers vs new Promise(setImmediate)
Posted
技术标签:
【中文标题】笑话:await vs setImmediate vs useFakeTimers vs new Promise(setImmediate)【英文标题】:Jest: await vs setImmediate vs useFakeTimers vs new Promise(setImmediate) 【发布时间】:2020-10-06 17:21:18 【问题描述】:接下来是 TypeScript 中的 Jest 测试。我想知道为什么需要 setImmediate() 。
第一个例子是一个有效的测试。接下来是我尝试过的各种不起作用的东西。我不明白发生了什么。 pubsub.publish 的签名是:
(method) PubSub.publish(triggerName: string, payload: any): Promise<void>
test.only('subscriptions', async () =>
const document = parse(`
subscription
create
`)
const sub = <AsyncIterator<ExecutionResult>>await subscribe(schema, document);
expect(sub.next).toBeDefined()
// setInterval and process.nextTick also work here:
setImmediate(() => pubsub.publish('CREATE_ONE', create: "FLUM!" )) // this works
const value: errors, data = await sub.next()
expect(errors).toBeUndefined()
expect(data).toBeDefined()
expect(data.create).toBe('FLUM!')
, 10000)
所以这些是我尝试过的其他方法,其中一些是在研究了类似问题的答案之后。所有这些尝试都失败,并在测试中出现超时异常:
test.only('subscriptions', async () =>
// attempt #1: jest.useFakeTimers()
const document = parse(`
subscription
create
`)
const sub = <AsyncIterator<ExecutionResult>>await subscribe(schema, document);
expect(sub.next).toBeDefined()
// #1, cont:
// pubsub.publish('CREATE_ONE', create: "FLUM!" )
// or...
// await pubsub.publish('CREATE_ONE', create: "FLUM!" )
// this works, though, like in previous test, but with fake timers:
// setImmediate(() => pubsub.publish('CREATE_ONE', create: "FLUM!" ))
// attempt #2:
// await pubsub.publish('CREATE_ONE', create: "FLUM!" )
// attempt #3:
// pubsub.publish('CREATE_ONE', create: "FLUM!" )
// await new Promise(setImmediate)
// attempt #3a (variant):
// await new Promise((resolve) => setImmediate(resolve));
const value: errors, data = await sub.next()
expect(errors).toBeUndefined()
expect(data).toBeDefined()
expect(data.create).toBe('FLUM!')
, 10000)
我了解 setImmediate 在事件循环中放置了一个函数,以便在任何未决 I/O 事件之后立即执行。我不确定为什么需要它,因为 pubsub.publish() 返回一个可以用 await 处理的 Promise,但在这种情况下会发生下一行 await sub.next() 永远不会被调用。
我的想法是在 pubsub.publish() 中有一个 setInterval 调用,并且 setImmediate 等待任何未决的 setInterval 事件完成(我对此的理解很模糊)。尝试 3 和 3a 是我在其他地方找到的执行此操作的机制,但在这种情况下它们似乎不起作用。
问题:为什么这个测试需要 setImmediate 才能通过?
【问题讨论】:
可能与publish()返回的AsyncIterator的延迟初始化有关? graphql-subscriptions 中有一个问题:github.com/apollographql/graphql-subscriptions/issues/201 【参考方案1】:所以我的困惑是由于 setImmediate 做什么和不做什么。这就是正在发生的事情:
// setInterval and process.nextTick also work here:
setImmediate(() => pubsub.publish('CREATE_ONE', create: "FLUM!" ))
const value: errors, data = await sub.next()
如果没有 setImmediate(),则在调用 sub.next() 之前发送发布事件,因此不会被捕获。您可能认为 setImmediate(或 process.nextTick)会立即执行发布功能,但不是。相反,setImmediate 会延迟发布调用足够长的时间以供 sub.next() 执行。
我现在将对 setImmediate 和 process.nextTick 的实际工作原理进行一些补救性阅读。
【讨论】:
以上是关于笑话:await vs setImmediate vs useFakeTimers vs new Promise(setImmediate)的主要内容,如果未能解决你的问题,请参考以下文章
node.js async.js nextTick vs setImmediate
node.js async.js nextTick vs setImmediate
异步 callback vs promise vs async/await