例
帶有兩個源文件的音頻播放器。瀏覽器需要選擇它所支持的源文件(如果都支持則任選一個):
<audiocontrols><sourcesrc="horse.ogg"type="audio/ogg"><sourcesrc="horse.mp3"type="audio/mpeg"> 您的瀏覽器不支持 audio 元素。</audio>
瀏覽器支持
IE 9+、Firefox、Opera、Chrome 和 Safari 都支持 <source> 標簽。
注釋:IE 8 或更早版本的 IE 瀏覽器都不支持 <source> 標簽。
標簽定義及使用說明
<source> 標簽為媒體元素(比如 <video> 和 <audio>)定義媒體資源。
<source> 標簽允許您規定兩個視頻/音頻文件共瀏覽器根據它對媒體類型或者編解碼器的支持進行選擇。
HTML 4.01 與 HTML5之間的差異
<source> 標簽是 HTML5 中的新標簽。
屬性
New:HTML5 中的新屬性。
屬性 | 值 | 描述 |
---|---|---|
mediaNew | media_query | 規定媒體資源的類型,供瀏覽器決定是否下載。 |
srcNew | URL | 規定媒體文件的 URL。 |
typeNew | MIME_type | 規定媒體資源的 MIME 類型。 |
全局屬性
<source> 標簽支持 HTML 的全局屬性。
事件屬性
<source> 標簽支持 HTML 的事件屬性。
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
音在HTML中可以以不同的方式播放.
問題以及解決方法
在 HTML 中播放音頻并不容易!
您需要諳熟大量技巧,以確保您的音頻文件在所有瀏覽器中(Internet Explorer, Chrome, Firefox, Safari, Opera)和所有硬件上(PC, Mac , iPad, iPhone)都能夠播放。
在這W3CSchool 為您總結了問題和解決方法。
使用插件
瀏覽器插件是一種擴展瀏覽器標準功能的小型計算機程序。
插件可以使用 <object> 標簽 或者 <embed> 標簽添加在頁面上.
這些標簽定義資源(通常非 HTML 資源)的容器,根據類型,它們即會由瀏覽器顯示,也會由外部插件顯示。
使用 <embed> 元素
<embed>標簽定義外部(非 HTML)內容的容器。(這是一個 HTML5 標簽,在 HTML4 中是非法的,但是所有瀏覽器中都有效)。
下面的代碼片段能夠顯示嵌入網頁中的 MP3 文件:
實例
<embed height="50" width="100" src="horse.mp3">
問題:
<embed> 標簽在 HTML 4 中是無效的。頁面無法通過 HTML 4 驗證。
不同的瀏覽器對音頻格式的支持也不同。
如果瀏覽器不支持該文件格式,沒有插件的話就無法播放該音頻。
如果用戶的計算機未安裝插件,無法播放音頻。
如果把該文件轉換為其他格式,仍然無法在所有瀏覽器中播放。
使用 <object> 元素
<object tag> 標簽也可以定義外部(非 HTML)內容的容器。
下面的代碼片段能夠顯示嵌入網頁中的 MP3 文件:
實例
<object height="50" width="100" data="horse.mp3"></object>
問題:
不同的瀏覽器對音頻格式的支持也不同。
如果瀏覽器不支持該文件格式,沒有插件的話就無法播放該音頻。
如果用戶的計算機未安裝插件,無法播放音頻。
如果把該文件轉換為其他格式,仍然無法在所有瀏覽器中播放。
使用 HTML5 <audio> 元素
HTML5 <audio> 元素是一個 HTML5 元素,在 HTML 4 中是非法的,但在所有瀏覽器中都有效。
The <audio> element works in all modern browsers.
以下我們將使用 <audio> 標簽來描述 MP3 文件(Internet Explorer、Chrome 以及 Safari 中是有效的), 同樣添加了一個 OGG 類型文件(Firefox 和 Opera瀏覽器中有效).如果失敗,它會顯示一個錯誤文本信息:
實例
<audio controls>
<source src="horse.mp3" type="audio/mpeg">
<source src="horse.ogg" type="audio/ogg">
Your browser does not support this audio format.
</audio>
問題:
<audio> 標簽在 HTML 4 中是無效的。您的頁面無法通過 HTML 4 驗證。
您必須把音頻文件轉換為不同的格式。
<audio> 元素在老式瀏覽器中不起作用。
最好的 HTML 解決方法
下面的例子使用了兩個不同的音頻格式。HTML5 <audio> 元素會嘗試以 mp3 或 ogg 來播放音頻。如果失敗,代碼將回退嘗試 <embed> 元素。
實例
<audio controls height="100" width="100">
<source src="horse.mp3" type="audio/mpeg">
<source src="horse.ogg" type="audio/ogg">
<embed height="50" width="100" src="horse.mp3">
</audio>
問題:
您必須把音頻轉換為不同的格式。
<embed> 元素無法回退來顯示錯誤消息。
雅虎媒體播放器 - 一個簡單的添加音頻到你網站上的方式
使用雅虎播放器是免費的。如需使用它,您需要把這段 JavaScript 插入網頁底部:
雅虎播放器可以播放MP3以及其他各種格式。你只需添加一行代碼到你的頁面或 博客中就可以輕松地將您的HTML頁面制作成 專業的播放列表:
實例
<a href="horse.mp3">Play Sound</a>
<script src="http://mediaplayer.yahoo.com/latest"></script>
如果你要使用它,您需要把這段 JavaScript 插入網頁底部:
<script src="http://mediaplayer.yahoo.com/latest"></script>
然后只需簡單地把 MP3 文件鏈接到您的 HTML 中,JavaScript 會自動地為每首歌創建播放按鈕:
<a href="song1.mp3">Play Song 1</a>
<a href="song2.wav">Play Song 2</a>
...
...
雅虎媒體播放器為您的用戶提供的是一個小型的播放按鈕,而不是完整的播放器。不過,當您點擊該按鈕,會彈出完整的播放器。
請注意,這個播放器始終??吭诖翱虻撞?。只需點擊它,就可將其滑出。
使用超鏈接
如果網頁包含指向媒體文件的超鏈接,大多數瀏覽器會使用"輔助應用程序"來播放文件。
以下代碼片段顯示指向 mp3 文件的鏈接。如果用戶點擊該鏈接,瀏覽器會啟動"輔助應用程序"來播放該文件:
實例
<a href="horse.mp3">Play the sound</a>
內聯的聲音說明
當您在網頁中包含聲音,或者作為網頁的組成部分時,它被稱為內聯聲音。
如果您打算在 web 應用程序中使用內聯聲音,您需要意識到很多人都覺得內聯聲音令人惱火。同時請注意,用戶可能已經關閉了瀏覽器中的內聯聲音選項。
我們最好的建議是只在用戶希望聽到內聯聲音的地方包含它們。一個正面的例子是,在用戶需要聽到錄音并點擊某個鏈接時,會打開頁面然后播放錄音。
HTML 多媒體標簽
New : HTML5 新標簽
標簽 | 描述 |
---|---|
<embed> | 定義內嵌對象。HTML4 中不贊成,HTML5 中允許。 |
<object> | 定義內嵌對象。 |
<param> | 定義對象的參數。 |
<audio>New | 定義了聲音內容 |
<video>New | 定義一個視頻或者影片 |
<source>New | 定義了media元素的多媒體資源(<video> 和 <audio>) |
<track>New | 規定media元素的字幕文件或其他包含文本的文件 (<video> 和<audio>) |
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
者|Lukas Gisder-Dubé
譯者|謝麗
本文將分三部分分析 JavaScript 中的錯誤,首先我們將了解錯誤的一般情況,之后,我們將關注后端(Node.js + Express.js),最后,我們將重點看下如何處理 React.js 中的錯誤。選擇這些框架,是因為它們是目前最流行的,但是,你應該也能夠將這些新發現應用到其他框架中吧!
繼上一篇文章 (https://link.medium.com/MO32x55aNR) 之后,我想談談錯誤。錯誤很好——我相信你以前聽過這個說法。乍一看,我們害怕錯誤,因為錯誤往往會涉及到在公共場合受到傷害或羞辱。通過犯錯誤,我們實際上學會了如何不去做某事,以及下次如何做得更好。
顯然,這是關于從現實生活的錯誤中學習。編程中的錯誤有點不同。它們為我們提供了很好的特征來改進我們的代碼,并告訴用戶什么地方出了問題(也可能是教他們如何修復它)。
GitHub(https://github.com/gisderdube/graceful-error-handling) 上提供了一個完整的樣例項目。
throw new Error('something went wrong')?會在 JavaScript 中創建一個錯誤實例,并停止腳本的執行,除非你對錯誤做了一些處理。當你作為 JavaScript 開發者開啟自己的職業生涯時,你自己很可能不會這樣做,但是,你已經從其他庫(或運行時)那里看到了,例如,類似“ReferenceError: fs 未定義”這樣的錯誤。
Error 對象
Error 對象有兩個內置屬性供我們使用。第一個是消息,作為參數傳遞給 Error 構造函數,例如 new Error(“這是錯誤消息”)。你可以通過 message 屬性訪問消息:
const myError=new Error(‘請改進代碼’) console.log(myError.message) // 請改進代碼
第二個是錯誤堆棧跟蹤,這個屬性非常重要。你可以通過 stack 屬性訪問它。錯誤堆棧將為你提供歷史記錄(調用堆棧),從中可以查看哪個文件導致了錯誤。堆棧的上部也包括消息,然后是實際的堆棧,從距離錯誤發生最近的點開始,一直到最外層“需要為錯誤負責”的文件:
Error: 請改進代碼 at Object.<anonymous> (/Users/gisderdube/Documents/_projects/hacking.nosync/error-handling/src/general.js:1:79) at Module._compile (internal/modules/cjs/loader.js:689:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10) at Module.load (internal/modules/cjs/loader.js:599:32) at tryModuleLoad (internal/modules/cjs/loader.js:538:12) at Function.Module._load (internal/modules/cjs/loader.js:530:3) at Function.Module.runMain (internal/modules/cjs/loader.js:742:12) at startup (internal/bootstrap/node.js:266:19) at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)
拋出和處理錯誤
現在,Error 實例本身不會導致任何結果,例如,new Error('...') 不會做任何事情。當錯誤被拋出時,就會變得更有趣。然后,如前所述,腳本將停止執行,除非你在流程中以某種方式對它進行了處理。記住,是手動拋出錯誤,還是由庫拋出錯誤,甚至由運行時本身(Node 或瀏覽器),都沒有關系。讓我們看看如何在不同的場景中處理這些錯誤。
try .... catch
這是最簡單但經常被遺忘的錯誤處理方法——多虧 async / await,它的使用現在又多了起來。它可以用來捕獲任何類型的同步錯誤,例如,如果我們不把 console.log(b) 放在一個 try … catch 塊中,腳本會停止執行。
… finally
有時候,不管是否有錯誤,代碼都需要執行。你可以使用第三個可選塊 finally。通常,這與在 try…catch 語句后面加一行代碼是一樣的,但它有時很有用。
異步性——回調
異步性,這是在使用 JavaScript 時必須考慮的一個主題。當你有一個異步函數,并且該函數內部發生錯誤時,你的腳本將繼續執行,因此,不會立即出現任何錯誤。當使用回調函數處理異步函數時(不推薦),你通常會在回調函數中收到兩個參數,如下所示:
如果有錯誤,err 參數就等同于那個錯誤。如果沒有,參數將是 undefined 或 null。要么在 if(err) 塊中返回某項內容,要么將其他指令封裝在 else 塊中,這一點很重要,否則你可能會得到另一個錯誤,例如,result 可能未定義,而你試圖訪問 result.data,類似這樣的情況。
異步性——Promises
處理異步性的更好方法是使用 Promises。在這一點上,除了代碼可讀性更強之外,我們還改進了錯誤處理。只要有一個 catch 塊,我們就不再需要太關注具體的錯誤捕獲。在鏈接 Promises 時,catch 塊捕獲會自 Promises 執行或上一個 catch 塊以來的所有錯誤。注意,沒有 catch 塊的 Promises 不會終止腳本,但會給你一條可讀性較差的消息,比如:
(node:7741) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: something went wrong (node:7741) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. */
因此,務必要在 Promises 中加入 catch 塊。
回到 try … catch
隨著 JavaScript 引入 async / await,我們回到了最初的錯誤處理方法,借助 try … catch … finally,錯誤處理變得非常簡單。
因為這和我們處理“普通”同步錯誤的方法是一樣的,所以如果需要的話,更容易使用作用域更大的 catch 語句。
現在,我們已經有了處理錯誤的工具,讓我們看下,我們在實際情況下能用它們做什么。后端錯誤的產生和處理是應用程序至關重要的組成部分。對于錯誤處理,有不同的方法。我將向你展示一個自定義 Error 構造函數和錯誤代碼的方法,我們可以輕松地傳遞到前端或任何 API 消費者。構建后端的細節并不重要,基本思路不變。
我們將使用 Express.js 作為路由框架。讓我們考慮下最有效的錯誤處理結構。我們希望:
構建一個自定義 Error 構造函數
我們將使用已有的 Error 構造函數并擴展它。繼承在 JavaScript 中是一件危險的事情,但根據我的經驗,在這種情況下,它非常有用。我們為什么需要它?我們仍然希望堆棧跟蹤給我們一個很好的調試體驗。擴展 JavaScript 原生 Error 構造函數可以讓我們方便地獲得堆棧跟蹤。我們唯一要做的是添加代碼(我們稍后可以通過錯誤代碼訪問)和要傳遞給前端的狀態(http 狀態代碼)。
如何處理路由
在完成 Error 的自定義之后,我們需要設置路由結構。正如我指出的那樣,我們想要一個單點真錯誤處理,就是說,對于每一個路由,我們要有相同的錯誤處理行為。在默認情況下,由于路由都是封裝的,所以 Express 并不真正支持那種方式。
為了解決這個問題,我們可以實現一個路由處理程序,并把實際的路由邏輯定義為普通的函數。這樣,如果路由功能(或任何內部函數)拋出一個錯誤,它將返回到路由處理程序,然后可以傳給前端。當后端發生錯誤時,我們可以用以下格式傳遞一個響應給前端——比如一個 JSON API:
{ error: 'SOME_ERROR_CODE', description: 'Something bad happened. Please try again or contact support.' }
準備好不知所措。當我說下面的話時,我的學生總是生我的氣:
如果你咋看之下并不是什么都懂,那沒問題。只要使用一段時間,你就會發現為什么要那樣。
順便說一下,這可以稱為自上而下的學習,我非常喜歡。
路由處理程序就是這個樣子:
我希望你能讀下代碼中的注釋,我認為那比我在這里解釋更有意義。現在,讓我們看下實際的路由文件是什么樣子:
在這些例子中,我沒有做任何有實際要求的事情,我只是假設不同的錯誤場景。例如,GET /city 在第 3 行結束,POST /city 在第 8 號結束等等。這也適用于查詢參數,例如,GET /city?startsWith=R。本質上,你會有一個未處理的錯誤,前端會收到:
{ error: 'GENERIC', description: 'Something went wrong. Please try again or contact support.' }
或者你將手動拋出 CustomError,例如:
throw new CustomError('MY_CODE', 400, 'Error description')
上述代碼會轉換成:
{ error: 'MY_CODE', description: 'Error description' }
既然我們有了這個漂亮的后端設置,我們就不會再把錯誤日志泄漏到前端,而總是返回有用的信息,說明出現了什么問題。
確保你已經在 GitHub(https://github.com/gisderdube/graceful-error-handling) 上看過完整的庫。你可以把它用在任何項目中,并根據自己的需要來修改它!
下一個也是最后一個步驟是管理前端的錯誤。這里,你要使用第一部分描述的工具處理由前端邏輯產生的錯誤。不過,后端的錯誤也要顯示。首先,讓我們看看如何顯示錯誤。如前所述,我們將使用 React 進行演練。
把錯誤保存在 React 狀態中
和其他數據一樣,錯誤和錯誤消息會變化,因此,你想把它們放在組件狀態中。在默認情況下,你想要在加載時重置錯誤,以便用戶第一次看到頁面時,不會看到錯誤。
接下來我們必須澄清的是不同錯誤類型及與其匹配的可視化表示。就像在后端一樣,有 3 種類型:
2 和 3 非常類似,雖然源頭不一樣,但如果你愿意,就可以在同樣的 state 中處理。我們將從代碼中看下如何實現。
我將使用 React 的原生 state 實現,但是,你還可以使用類似 MobX 或 Redux 這樣的狀態管理系統。
全局錯誤
通常,我將把這些錯誤保存在最外層的有狀態組件中,并渲染一個靜態 UI 元素,這可能是屏幕頂部的一個紅色橫幅、模態或其他什么東西,設計實現由你決定。
讓我們看下代碼:
正如你看到的那樣,Application.js 中的狀態存在錯誤。我們也有方法可以重置并改變錯誤的值。我們把值和重置方法傳遞給 GlobalError 組件,在點擊'x'時,該組件會顯示錯誤并重置它。讓我們看看 GlobalError 組件:
你可以看到,在第 5 行,如果沒有錯誤,我們就不做任何渲染。這可以防止我們的頁面上出現一個空的紅框。當然,你可以改變這個組件的外觀和行為。例如,你可以將“x”替換為 Timeout,幾秒鐘后重置錯誤狀態。
現在,你已經準備好在任何地方使用全局錯誤狀態了,只是從 Application.js 把 _setError 向下傳遞,而且,你可以設置全局錯誤,例如,當一個請求從后端返回了字段 error: 'GENERIC'。例如:
如果你比較懶,到這里就可以結束了。即使你有具體的錯誤,你總是可以改變全局錯誤狀態,并把錯誤提示框顯示在頁面頂部。不過,我將向你展示如何處理和顯示具體的錯誤。為什么?首先,這是關于錯誤處理的權威指南,所以我不能停在這里。其次,如果你只是把所有的錯誤都作為全局錯誤來顯示,那么體驗人員會瘋掉。
處理具體的請求錯誤
和全局錯誤類似,我們也有位于其他組件內部的局部錯誤狀態,過程相同:
有件事要記住,清除錯誤通常有一個不同的觸發器。用' x '刪除錯誤是沒有意義的。關于這一點,在發出新請求時清除錯誤會更有意義。你還可以在用戶進行更改時清除錯誤,例如當修改輸入值時。
源于前端的錯誤
如前所述,這些錯誤可以使用與處理后端具體錯誤相同的方式(狀態)進行處理。這次,我們將使用一個有輸入字段的示例,只允許用戶在實際提供以下輸入時刪除一個城市:
使用錯誤代碼實現錯誤國際化
也許你一直想知道為什么我們有這些錯誤代碼,例如 GENERIC ,我們只是顯示從后端傳遞過來的錯誤描述。現在,隨著你的應用越來越大,你就會希望征服新的市場,并在某個時候面臨多種語言支持的問題。如果你到了這個時候,你就可以使用前面提到的錯誤代碼使用用戶的語言來顯示恰當的描述。
我希望你對如何處理錯誤有了一些了解。忘掉 console.error(err),它現在已經是過去時了。可以使用它進行調試,但它不應該出現在最終的產品構建中。為了防止這種情況,我建議你使用日志庫,我過去一直使用 loglevel,我對它非常滿意。
英文原文
https://levelup.gitconnected.com/the-definite-guide-to-handling-errors-gracefully-in-javascript-58424d9c60e6
*請認真填寫需求信息,我們會在24小時內與您取得聯系。