如何排队或等到最后一个合并请求完成?

How to queue or wait until last Combine request done?

我有一个函数,每次只需要执行一次。我试图避免在尚未完成最后一个请求时调用函数。这是我正在尝试的:

import Combine
import Foundation
import PlaygroundSupport

var publisher1 = PassthroughSubject<Bool, Never>()
var publisher2 = PassthroughSubject<Void, Never>()
var cancellable = Set<AnyCancellable>()

func scheduleNotifications() -> Future <Void, Never> {
    Future() { promise in
        print("Started scheduling... \(Date())")

        DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
            promise(.success(()))
        }
    }
}

Publishers.Merge(
    publisher1
        .filter { [=10=] }
        .map { _ in },
    publisher2
)
.flatMap { scheduleNotifications() }
.sink { print("Complete: \(Date())") }
.store(in: &cancellable)

PlaygroundPage.current.needsIndefiniteExecution = true

如果 publisher1publisher2 触发,则调用 scheduleNotifications()。但是,在函数完成之前,publisher1 可能会触发并调用 scheduleNotifications():

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    publisher1.send(true)
}

DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
    publisher1.send(true)
}

这会打印:

Started scheduling... 2021-02-07 15:50:25 +0000
Started scheduling... 2021-02-07 15:50:27 +0000
Complete: 2021-02-07 15:50:35 +0000
Complete: 2021-02-07 15:50:38 +0000

这是一个问题,因为 scheduleNotifications 在添加之前删除了所有通知。因此,一秒钟后触发的第二个请求正在清除第一个请求仍在忙于构建的所有通知。

有没有办法让第二把火继续燃烧,直到 scheduleNotifications() 完成所有当前正在进行的工作?

我相信如果你使用append而不是flatMap,你会得到你想要的结果。

Publishers.Merge(publisher1, publisher2)
    .append(scheduleNotifications())
    .sink { print("Complete") }
    .store(in: &cancellable)

您可以使用 FlatMapmaxPublishers 参数实现此目的。限制为一个会对上游产生背压,直到最后一个生成的发布者完成:

Publishers.Merge(
    publisher1
        .filter { [=10=] }
        .map { _ in },
    publisher2
)
.flatMap(maxPublishers: .max(1)) {  // <- here
   scheduleNotifications() 
}
.sink { print("Complete: \(Date())") }
.store(in: &cancellable)