R Shiny中如何实现等待JavaScript输入返回结果?
R Shiny 服务端等待JS返回结果后执行后续代码的实现方案
Shiny前后端通信本身是异步机制,session$sendCustomMessage发完消息不会阻塞等待前端执行,直接运行后续代码时拿不到JS返回值是正常现象。注意不要在R端写硬阻塞逻辑等待返回——R是单线程模型,硬阻塞会直接冻结整个应用的交互响应。
正确实现方式是拆分执行逻辑,通过响应式标记控制执行时机,等JS通过Shiny.setInputValue把结果回传到服务端、对应input值更新后,再触发后续逻辑,修改后的可运行代码如下:
library(shiny) js <- ' Shiny.addCustomMessageHandler("bar", function(dummy) { Shiny.setInputValue("uniqueid", "Hello back"); }) ' ui <- shinyUI( fluidPage( tags$script(js), actionButton("foo", label = "Say hello") ) ) server <- shinyServer(function(input, output, session) { # 响应式标记:标识是否处于等待JS返回结果的状态 js_wait_flag <- reactiveVal(FALSE) observeEvent(input$foo, { # 标记进入等待状态 js_wait_flag(TRUE) # 向前端发送自定义消息触发JS逻辑 session$sendCustomMessage("bar", "hello") }) # 监听JS回传的input值,满足条件时执行后续逻辑 observeEvent(input$uniqueid, { # 校验条件:处于等待状态 + 回传值不为NULL req(js_wait_flag(), !is.null(input$uniqueid)) # 此处放置需要等JS返回后再执行的代码 print(input$uniqueid) # 执行完成后重置标记,避免重复触发 js_wait_flag(FALSE) }) }) shinyApp(ui, server)
注意事项
- 用
req()做前置校验,既可以避免app初始化时input$uniqueid为NULL误执行逻辑,也能确保只有主动触发JS调用后才会运行后续代码 - 多次触发场景下只要每次触发JS调用前把标记设为
TRUE即可,执行完自动重置,不会出现历史值残留导致的误触发 - 不要用
Sys.sleep()写轮询逻辑等待input更新,轮询会阻塞R的事件循环,期间整个app所有交互都会卡死无响应。
内容的提问来源于stack exchange,提问作者L. t.
相关产品推荐
相关产品推荐

