You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用future_promise优化Shiny的downloadHandler仍卡顿的问题求助

解决Shiny应用生成PDF时卡顿且无法响应输入的问题

你的核心问题是**downloadHandler的content函数是同步执行逻辑,直接嵌套future_promise无法实现真正的异步不阻塞**。浏览器的下载请求会等待content函数完成,导致主线程被间接阻塞,滑块等输入无法响应。以下是修正后的完整方案:

修正思路

  1. 将PDF生成与下载操作分离:用actionButton触发异步生成任务,而非直接绑定downloadHandler
  2. 用reactiveVal存储生成好的PDF路径,任务完成后再触发下载
  3. 添加状态提示与按钮禁用逻辑,避免重复操作并告知用户进度
  4. 用future_promise真正异步执行耗时的rmarkdown::render,确保主线程不被阻塞

修正后的Shiny应用代码

library(shiny)
library(promises)
library(future)
library(shinyjs)

plan(multisession)

ui <- fluidPage(
  useShinyjs(),
  titlePanel("Old Faithful Geyser Data"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      actionButton("generatePDF", "Generate PDF"),
      hidden(downloadButton("downloadPDF", "Download PDF")),
      textOutput("loading_status")
    ),
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

server <- function(input, output, session) {
  # 存储生成好的PDF文件路径
  generated_pdf <- reactiveVal(NULL)
  
  output$distPlot <- renderPlot({
    x    <- faithful[, 2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
    hist(x, breaks = bins, col = 'darkgray', border = 'white',
         xlab = 'Waiting time to next eruption (in mins)',
         main = 'Histogram of waiting times')
  })
  
  # 触发PDF异步生成任务
  observeEvent(input$generatePDF, {
    req(input$bins)
    varbins <- input$bins
    
    # 更新状态:显示加载提示、禁用生成按钮
    output$loading_status <- renderText("正在生成PDF,请稍候...")
    disable("generatePDF")
    hide("downloadPDF")
    
    # 异步执行PDF生成逻辑
    future_promise({
      tempReport <- file.path(tempdir(), "Histogram.Rmd")
      file.copy("Histogram.Rmd", tempReport, overwrite = TRUE)
      Sys.sleep(5) # 模拟耗时操作
      output_file <- tempfile(fileext = ".pdf")
      rmarkdown::render(tempReport, output_file = output_file,
                        params = list(vbins = varbins),
                        envir = new.env(parent = globalenv()))
      output_file
    }) %...>% {
      # 任务成功完成:更新路径、恢复按钮状态、显示下载按钮
      generated_pdf(.)
      output$loading_status <- renderText("PDF生成完成!")
      enable("generatePDF")
      show("downloadPDF")
    } %...!% {
      # 任务失败:提示错误、恢复按钮状态
      output$loading_status <- renderText("PDF生成失败,请重试!")
      enable("generatePDF")
    }
  })
  
  # 处理下载逻辑:读取已生成的PDF文件
  output$downloadPDF <- downloadHandler(
    filename = function() {
      paste("Histogram_", Sys.Date(), ".pdf", sep = "")
    },
    content = function(file) {
      file.copy(generated_pdf(), file)
    }
  )
}

shinyApp(ui = ui, server = server)

说明

  • 原Histogram.Rmd文件无需修改,保持你提供的代码即可
  • 优化点:
    • 生成PDF期间,滑块输入可正常响应,直方图实时更新
    • 加入加载状态提示,避免用户重复点击生成按钮
    • 下载文件名添加日期后缀,防止文件覆盖
    • 增加错误处理逻辑,生成失败时提示用户

内容的提问来源于stack exchange,提问作者rdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 19:15:55