如何为Combine发布器的事件设置最小间隔?
问题分析
你当前的代码问题在于:flatMap(maxPublishers: .max(1)) 配合固定1秒延迟的实现,会直接丢弃第一个事件延迟未完成时发送的后续事件。因为flatMap的maxPublishers参数限制了同时只能运行一个订阅发布器,当达到上限时,新事件会被忽略,直到当前发布器完成。这就是为什么你只看到1和4的输出——2、3发送时第一个延迟任务还在执行,所以被丢弃了。
正确实现方案
要满足所有输出事件之间至少间隔1秒,上游事件间隔大于1秒则正常输出的需求,需要保留所有上游事件,串行处理每个事件,同时跟踪上一次输出时间来动态计算当前事件的延迟时长。
import Combine let subject = PassthroughSubject<Int, Never>() // 记录上一次输出的时间,初始值设为遥远过去 var lastOutputTime = Date.distantPast let result = subject // 串行处理每个事件,保证前一个事件输出完成后再处理下一个 .flatMap(maxPublishers: .max(1)) { value -> AnyPublisher<Int, Never> in let currentTime = Date() // 计算当前时间与上一次输出时间的间隔 let timeSinceLastOutput = currentTime.timeIntervalSince(lastOutputTime) // 计算需要延迟的时间:如果间隔不足1秒,延迟补足到1秒;否则不延迟 let delayDuration = max(1.0 - timeSinceLastOutput, 0.0) return Just(value) .delay(for: .seconds(delayDuration), scheduler: RunLoop.main) // 更新上一次输出时间为当前事件的输出时间 .handleEvents(receiveOutput: { _ in lastOutputTime = Date() }) .eraseToAnyPublisher() } let cancellable = result.sink { print("--- value \($0) ---") } // 测试发送事件 subject.send(1) DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { subject.send(2) } DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { subject.send(3) } DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) { subject.send(4) }
运行效果
输出结果如下,事件间隔严格保证至少1秒:
--- value 1 --- --- value 2 --- --- value 3 --- --- value 4 ---
- 1立即输出;
- 2在1输出后1秒输出;
- 3在2输出后1秒输出;
- 4发送时距离3的输出时间不足1秒,自动延迟到3输出后1秒再输出。
内容的提问来源于stack exchange,提问作者Wujo
相关产品推荐
相关产品推荐

