又到了 kaopubear 的专栏时间,本文较长图多,真诚建议滑到文末 阅读原文 体验更加。阅读更多内容,也欢迎 阅读原文 移步我的博客。 第一次接触网页开发是两三年前的事,那时我曾经问过计划带我入门前端的前辈:入门前端的标准是什么。他当时用一种极平和的语气和我说:学会dubug。几年后的今天我即便也写过一点网页工具,但还是依然没能入门。反思一下:一是 JavaScript 学的不好,二就是不敢说自己有多少 debug 的能力。 遂放弃。 最近因为需要又要涉及一点网页工具开发,同时因为需求整体和 R 交互比较多于是决定用 R 的 Shiny 来搞一搞。 写了一个多星期我感觉 Shiny 确实解决了不熟悉前后端交互的人写网页的大多数问题,但如何 debug 的门槛还是摆在那里。比如前几天一个高手和我吐槽写 Shiny 时不知道改了什么突然不能正确运行了,更糟心的是还没有任何报错信息。当然,后来经过讨论发现其实并非没有报错信息,只是那时他没有找到而已。 这篇文章就结合最近学习的一点资料,大致聊聊在 Shiny 中 debug 的一些方法。 Shiny debug 主要有三个步骤,分别是调试(Debugging),追踪(Tracing)和错误处理(Error handling)。
Debugging 调试breakpoints 断点说到「断点」,我不由的想对 bug 说一句:
如果你知道哪一行的代码有错(这话本身就像bug)或者猜测很可能是哪里不对,就可以直接在所在行设置一个断点。Rstudio 只需在行号左边点一下鼠标就会出现红点提示标记成功。开始运行 Shiny 程序后会在断点处停止执行,然后就可以开始逐步执行进行代码调试了。 如上图所示,我们在 40 和 41 行设置了两个断点,现在点击 这个时候我们可以方便的查看环境中已有的变量,例如这里已经运行完毕的 现在环境中存在 x 和 bin 两个变量,同时在 console 的 说到缺点,目前 breakpoints 只可以在 Rstudio IDE 中使用,而且只能用于 小结如下: browser() 命令其实从上面 console 的截图也可以看到,断点就是执行了一次类
甚至你还可以把 小结如下 Tracing 追踪在许多情况下通过暂停执行来找问题比较困难,相反需要我们在程序运行时观察系统。对于 Shiny 的程序尤其如此,因为他不像 R 脚本那样线性运行。 Showcase ModeShiny 在启动时, 如果想要默认开启这一功能,可以在该 Shiny 目录下创建一个 DisplayMode: Showcase 小结如下 ![]() Reactive Log在 Shiny 中经常会用到响应对象,当开启 Reactive Log 之后,程序运行时除了可以告诉你正在执行哪些响应之外,日志还可以帮助你可视化展示响应对象之间的依赖关系。在开启一个新的 R session 时首先配置 ![]() 打印 tracing在各种编程语言中,一个万变不离其宗的调试技巧就是不停的输出。在 PHP 里面是不停的
进行上述修改后,运行 Shiny 每次调整 input 都会在 console 中打印输出。如下图所示 ![]() 小结如下 ![]() Shiny Server 进行 tracing如果你的程序运行在 server 端而非本地,每次 Shiny 程序运行都会生成 log 文件,默认的路径是 客户端和服务器端 Tracing一个 Shiny 程序包括 client (浏览器) 和 server (R 进程) 两部分。这两者通过 websocket连接,websocket 接收来自客户端的状态,例如输入控件新的赋值,同时发布来自服务器端的状态更改,例如新的输出。在一些比较复杂的情况下,你可以通过打开 trace 来跟踪 JSON 格式的 websocket 内容。 ![]() 如上图所示,在输出内容中,
Errors 错误跑程序最怕看到的就是报错,但是真要有问题了最希望看到的就是明确的报错。 R 报错在 Shiny 中大多数报错信息都是由R引起的,在 0.13.0 之后的 Shiny 版本中已经有了比较直观的报错形式,会直接给出哪里的程序出现了错误。这里首先人为引入一个报错,当 input 大于 40 的时候停止程序并且抛出 ![]() 运行程序后调整输入如果错误,可以观察 console 的输出内容: ![]() 首先直接观察颜色不同的部分,直接告诉我们 JavaScript errors目前 Shiny 有很多第三方 JavaScript 组件,有时如果使用上面几种方式都没有定位到错误相关问题或者没有看到报错信息,很可能是 JavaScript 中发生错误导致程序出现了bug。毕竟 Shiny 是个网页应用,各种和用户的交互少不了 JavaScript 的使用。 要进行 JavaScript 的调试在 Rstudio 就不灵了。如果你是通过 Rstudio 打开了一个单独 Shiny 页面,可以通过右键单击 Shiny页面,选择 ![]() 在 Shiny 中 UI 的每个部分都会有一个 id 参数,这个 id 对应的参数在浏览器中解析之后就是对应着 HTML 标签中的 id。在 HTML 中,这个 id 是必须唯一(区别于name)。因此,在Shiny的ui中每一个id参数也必须唯一。解析效果如下图所示: ![]() 如果你不小心在 UI 中写入了两个一样的 id,在上图中就有两个标签的 id 都是 a,程序运行后在 Rstudio 并不会抛出什么错误,但是在 Shiny 页面端的各种操作就进行不了。如果不在开发者模式下进行调试只能通过各种方法在 Rstudio 进行测试,但是如果打开 JavaScript 的 console,就会看到其实已经给出了明确的报错信息。 ![]() 当然,Chrome 开发者工具的用法是在太多,这也是我在文章开头提到的自己入门不了前端的原因之一。如果在你的 Shiny 中用到了大量 JavaScript 相关内容,或者需要定制很多 CSS 相关的内容,可以学习一下官方的开发者工具文档。 至此,也就简单的写完了 R Shiny debug 的三个主要步骤,其中提到的每一个用法在实际使用中都需要进一步深入学习。当然,每一个方法用到的频率也各有不同,可以根据个人的实际情况进行后续的练习。 One more thing:shinyjs写到这里本来文章就可以结束了,但是似乎总有哪里不对。 为什么在 Rstudio 的 console 里就不能查看 JavaScript 的 log 信息。要知道 Rstudio GUI 本身使用的就是 QT框架,其中的很多部分都可以理解为一个网页。从维基百科或者它自己的说明中都可以看出这一点。 ![]() ![]() 不信的话你也可以在 Rstuido 的每个 pane 里右击然后选择 ![]() 你会看到下面图所示的内容 ![]() 既然如此,没有理由不去解决这个不方便的问题。其实在 R 中有一个专门为 Shiny 提高 JavaScript 使用体验开发的R包,叫做shinyjs。这个包的存在让 Shiny 使用 JavaScript 变得强大和高效了很多。其中针对调试有两个专门的函数。 showLog
这个函数类似于 JavaScript 中的 logjs
这个函数则可以把信息输出到 JavaScript console 中方便进行调试。 例如下面一段代码: library(ShinyJavaScript) 运行后通过点击 button ,就可以把 ![]() 嗯,先写到这里吧。 我的学习材料
|
|