- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我用下面的最小示例模拟的场景是允许用户在长时间运行的下载过程中使用 Shiny App(单击 numericInput
控件并查看发生服务器端事件)正在发生(用 downloadHandler
中的 Sys.sleep(10)
模拟)。
在同步设置中,单击“下载”按钮时,用户仍然可以与 UI 元素进行交互,但其他 Shiny 计算(在本例中为 renderText
)会被放入队列中.我想要异步设置,下载在后台进行,用户仍然可以与 UI 元素交互并获得所需的输出(例如renderText
)。
我正在使用 callr::r_bg()
在 Shiny 中实现异步,但问题是我当前的 downloadHandler 代码不正确(mtcars
应该是正在下载,但代码无法完成下载,404 错误消息),我相信这是由于 downloadHandler
期望 content()
函数执行的特定方式所致被写入,而我编写 callr::r_bg()
的方式并不适合它。任何见解将不胜感激!
引用:
https://www.r-bloggers.com/2020/04/asynchronous-background-execution-in-shiny-using-callr/
最小示例:
library(shiny)
ui <- fluidPage(
downloadButton("download", "Download"),
numericInput("count",
NULL,
1,
step = 1),
textOutput("text")
)
server <- function(input, output, session) {
long_download <- function(file) {
Sys.sleep(10)
write.csv(mtcars, file)
}
output$download <- downloadHandler(
filename = "data.csv",
content = function(file) {
x <- callr::r_bg(
func = long_download,
args = list(file)
)
return(x)
}
)
observeEvent(input$count, {
output$text <- renderText({
paste(input$count)
})
})
}
shinyApp(ui, server)
最佳答案
我想出了一个解决方案,并学到了以下内容:
input$X
,所以很难以传统方式包含 react 性。解决方法是将 UI 呈现为隐藏的 downlodButton
,并由用户会看到的 actionButton
掩盖。以下过程促进了 react 性:用户点击 actionButton -> react 性更新 -> 当 react 性完成时(reactive()$is_alive() == FALSE
),使用 shinyjs::click
启动 downloadHandler
callr
函数放在 downloadHandler 中,而是将文件保存在 content arg 中。范围界定似乎有些困难,因为文件需要在 content
功能环境中可用reactive()$is_alive()
invalidateLater()
和切换全局变量 (download_once
) 对于防止 react 不断激活很重要。没有它,您的浏览器将无限期地不断下载文件——这种行为很可怕,并且对您的 Shiny 应用程序用户来说就像病毒一样!代码解决方案:
library(shiny)
library(callr)
library(shinyjs)
ui <- fluidPage(
shinyjs::useShinyjs(),
#creating a hidden download button, since callr requires an input$,
#but downloadButton does not natively have an input$
actionButton("start", "Start Long Download", icon = icon("download")),
downloadButton("download", "Download", style = "visibility:hidden;"),
p("You can still interact with app during computation"),
numericInput("count",
NULL,
1,
step = 1),
textOutput("text"),
textOutput("did_it_work")
)
long_job <- function() {
Sys.sleep(5)
}
server <- function(input, output, session) {
#start async task which waits 5 sec then virtually clicks download
long_run <- eventReactive(input$start, {
#r_bg by default sets env of function to .GlobalEnv
x <- callr::r_bg(
func = long_job,
supervise = TRUE
)
return(x)
})
#desired output = download of mtcars file
output$download <- downloadHandler(filename = "test.csv",
content = function(file) {
write.csv(mtcars, file)
})
#output that's meant to let user know they can still interact with app
output$text <- renderText({
paste(input$count)
})
download_once <- TRUE
#output that tracks progress of background task
check <- reactive({
invalidateLater(millis = 1000, session = session)
if (long_run()$is_alive()) {
x <- "Job running in background"
} else {
x <- "Async job in background completed"
if(isTRUE(download_once)) {
shinyjs::click("download")
download_once <<- FALSE
}
invalidateLater(millis = 1, session = session)
}
return(x)
})
output$did_it_work <- renderText({
check()
})
}
shinyApp(ui, server)
关于r - 如何在 Shiny App 的 downloadHandler 中使用 callr::r_bg,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69760709/
我用下面的最小示例模拟的场景是允许用户在长时间运行的下载过程中使用 Shiny App(单击 numericInput 控件并查看发生服务器端事件)正在发生(用 downloadHandler 中的
我是一名优秀的程序员,十分优秀!