我有一个闪亮的应用程序模块,其中使用
callr
在模块中进行 API 调用,结果显示在表格中。 API调用需要一些时间,我想显示一个实时或模拟的过程(尝试过闪亮的进度,这种方法有效,但信息不丰富)。想传达“有什么落后了,就有进步”。我不知道如何传递API调用的实时进度。然后,根据waiter包上的例子,添加了sleep。然而,这并没有达到目的。如果有更好的方法来显示真实进度,而不需要像示例中那样的 for 循环,那将是理想的。
我无法制作 API 调用的简化版本,所以我只是留下了评论。我不知道有任何开源,我可以使用 httr 等创建 API 调用的示例。
下面是我的工作代码,显示一个页面,但不显示任何进度
library(shiny)
library(waiter)
# Define the UI function for the API call module
AsyncApiCallModuleUI <- function(id) {
ns <- NS(id)
# waiterShowOnLoad(
# color = "#f7fff7",
# hostess_loader(
# "loader",
# preset = "circle",
# text_color = "black",
# class = "label-center",
# center_page = TRUE
# )
# )
shiny::actionButton(
inputId = ns("apiButton"), label = "Refresh API Call",
icon = icon("rocket")
)
}
AsyncApiCallModule <- function(id, args) {
shiny::moduleServer(id, function(input, output, session) {
# Create the progress bar
# progress <- shiny::Progress$new(session)
hostess <- Hostess$new("loader")
shiny::observe({
# Start the progress bar
# progress$set(message = "API call in progress", value = 0.1)
hostess$set(value = 0.1)
# r_bg API call goes gere
Sys.sleep(runif(1) / 2)
# Update the progress bar
# progress$inc(0.1) # Increment the progress bar by 10%
hostess$inc(0.1)
# Complete the progress bar
# progress$set(value = 1)
hostess$set(1)
# progress$close()
waiter_hide()
})
base::return(mtcars)
})
}
ui <- shiny::fluidPage(
useWaiter(),
useHostess(),
waiterShowOnLoad(
color = "#f7fff7",
hostess_loader(
"loader",
preset = "circle",
text_color = "black",
class = "label-center",
center_page = TRUE
)
),
shinyjs::useShinyjs(),
AsyncApiCallModuleUI("mtcars_srv"),
DT::dataTableOutput("mtcars_table")
)
server <- function(input, output, session) {
mtcars_result <- AsyncApiCallModule(
id = "mtcars_srv", args
)
output$mtcars_table <- DT::renderDataTable({
DT::datatable(mtcars_result)
})
}
shiny::shinyApp(ui, server)
静态 R Markdown 文档不支持闪亮的应用程序
创建于 2024-03-21,使用 reprex v2.1.0
以下是如何在 JavaScript 中使用进度条执行下载。
文件 xhr.js,放入应用程序的 www 子文件夹中:
Shiny.addCustomMessageHandler("xhr", function (x) {
// 1. Create a new XMLHttpRequest object
let xhr = new XMLHttpRequest();
// 2. Configure it: GET-request for the URL
let url = "https://raw.githubusercontent.com/stla/bigjson/main/bigjson.json";
xhr.open("GET", url);
// 3. Send the request over the network
xhr.send();
// 4. This will be called after the response is received
let response; // variable to store the downloaded file
xhr.onload = function () {
if (xhr.status != 200) {
// analyze HTTP status of the response
alert(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found
} else {
// show the result in the console
console.log(`Done, got ${xhr.response.length} bytes`); // response is the server response
// store the response
// we don't send the response to Shiny here because it would block the progress bar
response = xhr.response;
}
};
let i = 1000; // this is used to slow down the communication with Shiny
let totalSize = 100293197; // the size of the downloaded file
let nsteps = 5; // number of steps for the progress bar
let threshold = 1 / nsteps;
xhr.onprogress = function (event) {
if (event.lengthComputable) { // if available, totalSize is not needed
// because it is given in event.total
let ratio = event.loaded / event.total;
if (ratio >= threshold) {
setTimeout(function () {
Shiny.setInputValue("received", ratio);
if (ratio === 1) { // send response to Shiny
Shiny.setInputValue("download", response);
}
}, i);
threshold += 1 / nsteps;
}
} else { // event.total is not available
let ratio = event.loaded / totalSize;
if (ratio >= threshold) {
setTimeout(function () {
Shiny.setInputValue("received", ratio);
if (ratio === 1) { // send response to Shiny
Shiny.setInputValue("download", response);
}
}, i);
threshold += 1 / nsteps;
}
}
i += 1000;
};
xhr.onerror = function () {
alert("Request failed");
};
});
我在这里下载了 Github 上托管的文件。
lengthComputable
事件的onprogress
为false
;这意味着这个事件并没有提供下载的总大小,然后我们必须手动输入。
应用程序:
library(shiny)
ui <- fluidPage(
tags$head(tags$script(src = "xhr.js")),
br(),
actionButton("go", "Go"),
br(),
tags$h2("Response will appear here:"),
verbatimTextOutput("response")
)
server <- function(input, output, session) {
# progress bar
progress <- NULL
observeEvent(input$go, {
progress <<- Progress$new(session, min = 0, max = 1)
progress$set(message = "Download in progress")
# trigger the download in JavaScript
session$sendCustomMessage("xhr", TRUE)
})
# input$received contains the ratio of the download in progress
observeEvent(input$received, {
progress$set(value = input$received)
if(input$received == 1) {
progress$close()
}
})
# input$download contains the downloaded file (here a JSON string)
output$response <- renderPrint({
req(input$download)
substr(input$download, 1, 100)
})
}
shinyApp(ui, server)