仅当某个操作花费的时间比预期长时,​​如何显示闪亮的模态?

How to show a shiny modal only if a certain operation takes longer than expected?

我有一个闪亮的小应用程序,它执行的操作有时是即时的,有时需要几秒钟。在后一种情况下,我想显示一个模式。如果操作需要很长时间,则以下方法效果很好;但它也会在即时操作中闪烁模态几毫秒;这很丑。

library(shiny)

ui <- fluidPage(
  # In the real app, there is only one operation that can either be fast or slow. 
  # The buttons in this example represent both possible scenarios.
  actionButton("slowButton", "save slow"),
  actionButton("fastButton", "save fast")
)

server <- function(input, output, session) {
  observeEvent(input$slowButton, {
    showModal(modalDialog("Saving..."))
    Sys.sleep(3)
    removeModal()
  })

  observeEvent(input$fastButton, {
    # The modal should be suppressed here, because the operation is fast enough.
    showModal(modalDialog("Saving..."))
    Sys.sleep(0)  # In reality, we do not know how long this takes.
    removeModal()
  })

}

shinyApp(ui, server)

有没有一种方法可以添加延迟以仅在操作时间超过半秒时才显示模态?

这是我在评论中概述的示例。然而,对于仅0.5s的延迟时间来显示模态,创建后台进程的开销可能太大了。

library(shiny)
library(shinyjs)
library(callr)

ui <- fluidPage(
  useShinyjs(),
  actionButton("saveButton", "save"),
)

server <- function(input, output, session) {
  rv <- reactiveValues(bg_process = NULL, retry_count = 0)
  
  observeEvent(input$saveButton, {
    disable("saveButton")
    unknown_duration <- round(runif(1L, max = 2L), digits = 1)
    print(paste0(Sys.time(), " - unknown process duration: ", unknown_duration, "s"))
    rv$bg_process <- r_bg(
      func = function(duration){
        Sys.sleep(duration)
        return("result")
      },
      args = list(duration = unknown_duration))
  })
  
  observe({
    req(rv$bg_process)
    if (rv$bg_process$poll_io(0)["process"] == "ready") {
      print(paste(Sys.time(), "-", rv$bg_process$get_result()))
      rv$retry_count <- 0
      enable("saveButton")
      removeModal()
      if(rv$bg_process$is_alive() == FALSE){
        rv$bg_process <- NULL # reset
      }
    } else {
      invalidateLater(1000)
      if(isolate({rv$retry_count}) == 3L){
        print(paste(Sys.time(), "- showModal"))
        showModal(modalDialog("Saving...")) 
      } else {
        print(paste(Sys.time(), "- waiting"))
      }
    }
    isolate({rv$retry_count <- rv$retry_count + 1})
  })
  
}

shinyApp(ui, server)