在看了一些關於HTML5 Audio API的資源后,一下子熱情高漲順勢寫了個音樂頻譜效果的作品來玩味,也就是上上篇博文里介紹的。今天在測試的時候發現三個問題處理得不是很好:
- 當歌曲正在播放的時候再選擇另一首,頁面頂部的標題沒有很好地更新
- 對於有些音頻文件,比如在上篇博文中提供的示例音樂里面,bbc_sherlock_openning.mp3這個文件在播放完畢后頻譜居然不會歸零!
- 另一個問題就是重點了,歌曲播放完了后后台代碼仍在不停地跑
結論
鑒於后面的內容是跟具體程序有關的(上上篇博文中介紹的Audio Visualizer),所以不知道源碼的你或許不太感興趣,於是把結論提前。
我想說的就是, 在JavaScript中遞歸使用了setTimeout或者setInterval,或者requestAnimationFrame(這個方法本身要求你遞歸使用),如果你的代碼有結束條件,最好在遞歸滿足結束條件后調用clearTimeout/clearInterval,cancleAnimationFrame來結束這些方法的運行。
就比如在問題三當中,我用的requestAnimationFrame來寫的動畫,當歌曲播放完畢,調用cancleAnimationFrame來清理之前設置的requestAnimationFrame以釋放內存。
下面是個關於取消requestAnimationFrame的簡單例子,來自css-tricks:
var globalID; function repeatOften() { $("<div />").appendTo("body"); globalID = requestAnimationFrame(repeatOften); } $("#start").on("click", function() { globalID = requestAnimationFrame(repeatOften); }); $("#stop").on("click", function() { cancelAnimationFrame(globalID); });
Question 1
第一個問題是用戶體驗的問題,很好解決,所以對於頁面頂部的infobar作了如下調整:
- 程序開始顯示程序名稱"HTML5 Audio API showcase | An Audio Viusalizer"
- 用戶選擇文件或者拖拽文件到頁面后,顯示相應的后台操作,比如"文件上傳中。。。","文件解碼中。。。",etc.
- 途中出錯則顯示相應錯誤信息,比如"!解碼失敗",如果一切順利,則音樂開始播放並顯示當前播放的文件名,同時將文字淡下去,讓主題頻譜更好地呈現
- 歌曲順利結束,頂部信息恢復正常顯示,同時更新標題到最開始狀態,也就是顯示程序名
- 如果歌曲播放過程中用戶選擇了另外的文件,頂部信息恢復正常顯示並且轉到步驟2
Question 2
第二個問題,出乎我的意料,同時也想不通,不妨先來重現一下。
下圖便是播放bbc_sherlock_openning.mp3完畢后的畫面,程序就這樣停留在了這樣的一個畫面,有三根頻譜條沒有歸零。我硬盤里大部分歌曲都被我跑過了都沒問題,但才看了<神探夏洛克>的我執意要拿它的片頭曲來爽一把,然后就發現問題了。
我不認為是程序的問題,又無奈想不出這文件有什么問題,於是只能來硬的了。進行人工干預,在每首歌曲播放完畢后手動將從歌曲里面獲取的值也就是analyser設為0,這樣所有頻譜條都會沒有問題了。算是個笨拙的解決方法吧,因為沒有打到問題的根源。
具體代碼可以去下載最新版本的源碼查看。之前的代碼都有注釋,后來加的這些注釋不詳細,所以我自認為有點晦澀難懂。
Question 3
對於第三個問題,其實原因我知道,也知道如何解決,只是在創建程序時沒有好的方案來組織代碼避免其他問題。今天再次進行編碼時得到了解決。
解決之前,不妨先來看開發者工具中顯示的信息。
- 選擇文件進行播放
- F12打開高度工具,切到時間軸(Timeline)面板,選擇內存(memory)
- 點擊'記錄按鈕(Record)' 開始監視代碼執行過程中的內存及運行狀況
這是歌曲播放過程中,還看不出什么端倪。等待歌曲結束繼續觀測。
從上圖可以看出,即使歌曲結束,內存還是呈現規律地起伏,我們期望的是它穩定,並且上方的記錄數隨時間推進也在增加,說明后台代碼正在運行。
原因是代碼中使用了requestAnimationFrame設置動畫,並且每選擇一首歌后,都又會重新建立新的requestAnimationFrame來進行動畫,而前面的requestAnimationFrame沒有消失仍然存在,這樣一來,一首接一首的歌曲后可以預見到瀏覽器崩潰的情況。
解決方法也就是前面說的適時地調用cancelAnimationFrame來清理之前設置的動畫。
下圖展示了改進后的情況。可以看到,歌曲播放完畢后,記錄數停止了增加,說明后台代碼沒有再運行了,並且等待了一段時間后圖中的內存也處於穩定狀態,沒有起伏。