我正在尝试构建一个闪亮的应用程序,通过不同的render *函数输出多个结果。
问题是其中一个结果需要一些时间来计算。所以我希望能够尽快呈现快速的结果。
以下是一些代码来说明
# ui.R
library(shiny)
shinyUI(fluidPage(
textOutput("res1"),
textOutput('res2')
))
# server.R
library(shiny)
shinyServer(function(input, output) {
output$res1 = renderText({
"shows up instantly"
})
output$res2 = renderText({
Sys.sleep(3)
"shows up after 3 sec"
})
})
目前,网页保持空白状态3秒钟,同时渲染两个元素。
我的问题如下:是否有可能强制output$res1
在output$res2
之前执行,并且在长计算开始之前将其结果发送到浏览器?
答案 0 :(得分:2)
签出invalidateLater否则,如果您只想渲染文本,可以使用以下方式将文本直接发送到客户端:
# ui.R
library(shiny)
ui <- shinyUI(fluidPage(
tags$head(
tags$script(
HTML("
Shiny.addCustomMessageHandler ('print',function (message) {
$('#'+message.selector).html(message.html);
console.log(message);
});
")
)
),
textOutput("res1"),
textOutput('res2')
))
# server.R
server <- shinyServer(function(input, output, session) {
session$sendCustomMessage(type = 'print', message = list(selector = 'res1', html = "shows up instantly"))
Sys.sleep(3)
session$sendCustomMessage(type = 'print', message = list(selector = 'res2', html = "shows up after 3 sec"))
})
shinyApp(ui = ui, server = server)
答案 1 :(得分:2)
我找到了解决方法。我们的想法是强制所有render*
函数在启动长计算之前将结果发送到浏览器。
在以下代码中,两个文本区域立即显示,第二个文本区域在3秒后更新。
shinyServer(function(input, output,session) {
status=reactiveValues(res1IsDone=FALSE,res2HasRendered=FALSE)
output$res1 = renderText({
status$res1IsDone = TRUE
"shows up instantly"
})
output$res2 = renderText({
if(isolate(!status$res1IsDone || !status$res2HasRendered)) {
status$res2HasRendered = TRUE
invalidateLater(100,session)
"wait"
} else {
Sys.sleep(3)
"shows up after 3 sec"
}
})
})
根据我的理解,闪亮是单线程的,一旦所有render*
函数执行一次(或者所有失效都被解决了?),结果就会被发送回浏览器。