又到了 kaopubear 的專欄時間,本文較長圖多,真誠建議滑到文末 閱讀原文 體驗更加。閱讀更多內(nèi)容,也歡迎 閱讀原文 移步我的博客。 第一次接觸網(wǎng)頁開發(fā)是兩三年前的事,那時我曾經(jīng)問過計劃帶我入門前端的前輩:入門前端的標(biāo)準(zhǔn)是什么。他當(dāng)時用一種極平和的語氣和我說:學(xué)會dubug。幾年后的今天我即便也寫過一點網(wǎng)頁工具,但還是依然沒能入門。反思一下:一是 JavaScript 學(xué)的不好,二就是不敢說自己有多少 debug 的能力。 遂放棄。 最近因為需要又要涉及一點網(wǎng)頁工具開發(fā),同時因為需求整體和 R 交互比較多于是決定用 R 的 Shiny 來搞一搞。 寫了一個多星期我感覺 Shiny 確實解決了不熟悉前后端交互的人寫網(wǎng)頁的大多數(shù)問題,但如何 debug 的門檻還是擺在那里。比如前幾天一個高手和我吐槽寫 Shiny 時不知道改了什么突然不能正確運行了,更糟心的是還沒有任何報錯信息。當(dāng)然,后來經(jīng)過討論發(fā)現(xiàn)其實并非沒有報錯信息,只是那時他沒有找到而已。 這篇文章就結(jié)合最近學(xué)習(xí)的一點資料,大致聊聊在 Shiny 中 debug 的一些方法。 Shiny debug 主要有三個步驟,分別是調(diào)試(Debugging),追蹤(Tracing)和錯誤處理(Error handling)。
Debugging 調(diào)試breakpoints 斷點說到「斷點」,我不由的想對 bug 說一句:
如果你知道哪一行的代碼有錯(這話本身就像bug)或者猜測很可能是哪里不對,就可以直接在所在行設(shè)置一個斷點。Rstudio 只需在行號左邊點一下鼠標(biāo)就會出現(xiàn)紅點提示標(biāo)記成功。開始運行 Shiny 程序后會在斷點處停止執(zhí)行,然后就可以開始逐步執(zhí)行進(jìn)行代碼調(diào)試了。 如上圖所示,我們在 40 和 41 行設(shè)置了兩個斷點,現(xiàn)在點擊 這個時候我們可以方便的查看環(huán)境中已有的變量,例如這里已經(jīng)運行完畢的 現(xiàn)在環(huán)境中存在 x 和 bin 兩個變量,同時在 console 的 說到缺點,目前 breakpoints 只可以在 Rstudio IDE 中使用,而且只能用于 小結(jié)如下: browser() 命令其實從上面 console 的截圖也可以看到,斷點就是執(zhí)行了一次類
甚至你還可以把 小結(jié)如下 Tracing 追蹤在許多情況下通過暫停執(zhí)行來找問題比較困難,相反需要我們在程序運行時觀察系統(tǒng)。對于 Shiny 的程序尤其如此,因為他不像 R 腳本那樣線性運行。 Showcase ModeShiny 在啟動時, 如果想要默認(rèn)開啟這一功能,可以在該 Shiny 目錄下創(chuàng)建一個 DisplayMode: Showcase 小結(jié)如下 ![]() Reactive Log在 Shiny 中經(jīng)常會用到響應(yīng)對象,當(dāng)開啟 Reactive Log 之后,程序運行時除了可以告訴你正在執(zhí)行哪些響應(yīng)之外,日志還可以幫助你可視化展示響應(yīng)對象之間的依賴關(guān)系。在開啟一個新的 R session 時首先配置 ![]() 打印 tracing在各種編程語言中,一個萬變不離其宗的調(diào)試技巧就是不停的輸出。在 PHP 里面是不停的
進(jìn)行上述修改后,運行 Shiny 每次調(diào)整 input 都會在 console 中打印輸出。如下圖所示 ![]() 小結(jié)如下 ![]() Shiny Server 進(jìn)行 tracing如果你的程序運行在 server 端而非本地,每次 Shiny 程序運行都會生成 log 文件,默認(rèn)的路徑是 客戶端和服務(wù)器端 Tracing一個 Shiny 程序包括 client (瀏覽器) 和 server (R 進(jìn)程) 兩部分。這兩者通過 websocket連接,websocket 接收來自客戶端的狀態(tài),例如輸入控件新的賦值,同時發(fā)布來自服務(wù)器端的狀態(tài)更改,例如新的輸出。在一些比較復(fù)雜的情況下,你可以通過打開 trace 來跟蹤 JSON 格式的 websocket 內(nèi)容。 ![]() 如上圖所示,在輸出內(nèi)容中,
Errors 錯誤跑程序最怕看到的就是報錯,但是真要有問題了最希望看到的就是明確的報錯。 R 報錯在 Shiny 中大多數(shù)報錯信息都是由R引起的,在 0.13.0 之后的 Shiny 版本中已經(jīng)有了比較直觀的報錯形式,會直接給出哪里的程序出現(xiàn)了錯誤。這里首先人為引入一個報錯,當(dāng) input 大于 40 的時候停止程序并且拋出 ![]() 運行程序后調(diào)整輸入如果錯誤,可以觀察 console 的輸出內(nèi)容: ![]() 首先直接觀察顏色不同的部分,直接告訴我們 JavaScript errors目前 Shiny 有很多第三方 JavaScript 組件,有時如果使用上面幾種方式都沒有定位到錯誤相關(guān)問題或者沒有看到報錯信息,很可能是 JavaScript 中發(fā)生錯誤導(dǎo)致程序出現(xiàn)了bug。畢竟 Shiny 是個網(wǎng)頁應(yīng)用,各種和用戶的交互少不了 JavaScript 的使用。 要進(jìn)行 JavaScript 的調(diào)試在 Rstudio 就不靈了。如果你是通過 Rstudio 打開了一個單獨 Shiny 頁面,可以通過右鍵單擊 Shiny頁面,選擇 ![]() 在 Shiny 中 UI 的每個部分都會有一個 id 參數(shù),這個 id 對應(yīng)的參數(shù)在瀏覽器中解析之后就是對應(yīng)著 HTML 標(biāo)簽中的 id。在 HTML 中,這個 id 是必須唯一(區(qū)別于name)。因此,在Shiny的ui中每一個id參數(shù)也必須唯一。解析效果如下圖所示: ![]() 如果你不小心在 UI 中寫入了兩個一樣的 id,在上圖中就有兩個標(biāo)簽的 id 都是 a,程序運行后在 Rstudio 并不會拋出什么錯誤,但是在 Shiny 頁面端的各種操作就進(jìn)行不了。如果不在開發(fā)者模式下進(jìn)行調(diào)試只能通過各種方法在 Rstudio 進(jìn)行測試,但是如果打開 JavaScript 的 console,就會看到其實已經(jīng)給出了明確的報錯信息。 ![]() 當(dāng)然,Chrome 開發(fā)者工具的用法是在太多,這也是我在文章開頭提到的自己入門不了前端的原因之一。如果在你的 Shiny 中用到了大量 JavaScript 相關(guān)內(nèi)容,或者需要定制很多 CSS 相關(guān)的內(nèi)容,可以學(xué)習(xí)一下官方的開發(fā)者工具文檔。 至此,也就簡單的寫完了 R Shiny debug 的三個主要步驟,其中提到的每一個用法在實際使用中都需要進(jìn)一步深入學(xué)習(xí)。當(dāng)然,每一個方法用到的頻率也各有不同,可以根據(jù)個人的實際情況進(jìn)行后續(xù)的練習(xí)。 One more thing:shinyjs寫到這里本來文章就可以結(jié)束了,但是似乎總有哪里不對。 為什么在 Rstudio 的 console 里就不能查看 JavaScript 的 log 信息。要知道 Rstudio GUI 本身使用的就是 QT框架,其中的很多部分都可以理解為一個網(wǎng)頁。從維基百科或者它自己的說明中都可以看出這一點。 ![]() ![]() 不信的話你也可以在 Rstuido 的每個 pane 里右擊然后選擇 ![]() 你會看到下面圖所示的內(nèi)容 ![]() 既然如此,沒有理由不去解決這個不方便的問題。其實在 R 中有一個專門為 Shiny 提高 JavaScript 使用體驗開發(fā)的R包,叫做shinyjs。這個包的存在讓 Shiny 使用 JavaScript 變得強大和高效了很多。其中針對調(diào)試有兩個專門的函數(shù)。 showLog
這個函數(shù)類似于 JavaScript 中的 logjs
這個函數(shù)則可以把信息輸出到 JavaScript console 中方便進(jìn)行調(diào)試。 例如下面一段代碼: library(ShinyJavaScript) 運行后通過點擊 button ,就可以把 ![]() 嗯,先寫到這里吧。 我的學(xué)習(xí)材料
|
|