Shiny开发:App完全加载后如何解绑加载提示且不增加Sys.sleep
实现方案
完全不需要调整后端Sys.sleep的等待时长,只需将加载提示的隐藏控制逻辑从后端迁移到前端,利用浏览器端的定时器实现视觉层面的延迟消失即可。这个等待过程不会占用服务器计算资源,也不会拖慢实际内容的渲染速度,实现加载提示与内容渲染的完全解绑。
核心修改逻辑
- 移除原有冗余逻辑:
- 删掉
renderPlot内部的shinyjs::hide("loadmessage")调用,不再通过后端代码控制加载提示的显示/隐藏 - 移除原有的
conditionalPanel条件判断,将加载提示的DOM节点直接固定在页面中,初始状态设置为隐藏
- 删掉
- 新增前端事件监听逻辑:
- 监听Shiny自带的全局
shiny:busy事件:应用进入后台计算状态时,立刻显示加载提示条,同时清除上一次残留的延时定时器,避免逻辑冲突 - 监听Shiny自带的全局
shiny:idle事件:后台计算完成、渲染资源已经准备就绪时,不立刻移除加载提示,而是启动浏览器端的延时定时器,等待自定义的时长后再将提示条淡出隐藏
- 监听Shiny自带的全局
- 加载提示条原有样式无需做任何调整。
修改后的完整可运行代码
library(shiny) runApp(list( ui = pageWithSidebar( headerPanel("Test"), sidebarPanel( tags$head(tags$style(type="text/css", " #loadmessage { position: fixed; top: 0px; left: 0px; width: 100%; padding: 5px 0px 5px 0px; text-align: center; font-weight: bold; font-size: 100%; color: #000000; background-color: #CCFF66; z-index: 105; } ")), # 前端控制脚本 tags$script(HTML(" $(document).on('shiny:connected', function() { // 初始化:隐藏加载提示 $('#loadmessage').hide(); // 计算开始时显示提示 $(document).on('shiny:busy', function() { $('#loadmessage').show(); // 清理上一次的定时器,避免逻辑冲突 if (window.loadHideTimer) { clearTimeout(window.loadHideTimer); } }); // 计算结束时延迟隐藏提示 $(document).on('shiny:idle', function() { // 修改下方数字即可调整加载提示的额外停留时长,单位为毫秒,和后端Sys.sleep完全独立 window.loadHideTimer = setTimeout(function() { $('#loadmessage').fadeOut(300); }, 1000); }); }); ")), numericInput('n', 'Number of obs', 100), # 固定放置加载提示节点,不再绑定条件判断 tags$div("Loading...", id="loadmessage") ), mainPanel(plotOutput('plot')) ), server = function(input, output) { output$plot <- renderPlot({ # 原有Sys.sleep时长完全不需要改动 Sys.sleep(2) hist(runif(input$n)) }) } ))
关键说明
- 脚本中
setTimeout的第二个参数(示例值为1000)就是加载提示在计算完成后额外停留的时长,可根据需求自由调整,不会对后端计算流程产生任何影响 - 定时器清理逻辑可以避免用户连续快速调整输入参数时,旧的定时器提前触发导致加载提示异常消失的问题
- 改造完成后完全不需要依赖
shinyjs包,减少了不必要的资源加载
内容的提问来源于stack exchange,提问作者Nader Mehri
相关产品推荐
相关产品推荐

