W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
瀏覽器允許我們跟蹤外部資源的加載 —— 腳本,iframe,圖片等。
這里有兩個(gè)事件:
onload
? —— 成功加載,onerror
? —— 出現(xiàn) error。假設(shè)我們需要加載第三方腳本,并調(diào)用其中的函數(shù)。
我們可以像這樣動(dòng)態(tài)加載它:
let script = document.createElement('script');
script.src = "my.js";
document.head.append(script);
……但如何運(yùn)行在該腳本中聲明的函數(shù)?我們需要等到該腳本加載完成,之后才能調(diào)用它。
請(qǐng)注意:
對(duì)于我們自己的腳本,可以使用 JavaScript module,但是它們并未被廣泛應(yīng)用于第三方庫(kù)。
我們的得力助手是 ?load
? 事件。它會(huì)在腳本加載并執(zhí)行完成時(shí)觸發(fā)。
例如:
let script = document.createElement('script');
// 可以從任意域(domain),加載任意腳本
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);
script.onload = function() {
// 該腳本創(chuàng)建了一個(gè)變量 "_"
alert( _.VERSION ); // 顯示庫(kù)的版本
};
因此,在 onload
中我們可以使用腳本中的變量,運(yùn)行函數(shù)等。
……如果加載失敗怎么辦?例如,這里沒(méi)有這樣的腳本(error 404)或者服務(wù)器宕機(jī)(不可用)。
發(fā)生在腳本加載期間的 error 會(huì)被 error
事件跟蹤到。
例如,我們請(qǐng)求一個(gè)不存在的腳本:
let script = document.createElement('script');
script.src = "https://example.com/404.js"; // 沒(méi)有這個(gè)腳本
document.head.append(script);
script.onerror = function() {
alert("Error loading " + this.src); // Error loading https://example.com/404.js
};
請(qǐng)注意,在這里我們無(wú)法獲取更多 HTTP error 的詳細(xì)信息。我們不知道 error 是 404 還是 500 或者其他情況。只知道是加載失敗了。
重要:
onload
/onerror
事件僅跟蹤加載本身。
在腳本處理和執(zhí)行期間可能發(fā)生的 error 超出了這些事件跟蹤的范圍。也就是說(shuō):如果腳本成功加載,則即使腳本中有編程 error,也會(huì)觸發(fā)
onload
事件。如果要跟蹤腳本 error,可以使用window.onerror
全局處理程序。
load
和 error
事件也適用于其他資源,基本上(basically)適用于具有外部 src
的任何資源。
例如:
let img = document.createElement('img');
img.src = "https://js.cx/clipart/train.gif"; // (*)
img.onload = function() {
alert(`Image loaded, size ${img.width}x${img.height}`);
};
img.onerror = function() {
alert("Error occurred while loading image");
};
但是有一些注意事項(xiàng):
<img>
? 是個(gè)例外。它要等到獲得 src (?*
?) 后才開(kāi)始加載。<iframe>
? 來(lái)說(shuō),iframe 加載完成時(shí)會(huì)觸發(fā) ?iframe.onload
? 事件,無(wú)論是成功加載還是出現(xiàn) error。這是出于歷史原因。
這里有一條規(guī)則:來(lái)自一個(gè)網(wǎng)站的腳本無(wú)法訪問(wèn)其他網(wǎng)站的內(nèi)容。例如,位于 https://facebook.com
的腳本無(wú)法讀取位于 https://gmail.com
的用戶郵箱。
或者,更確切地說(shuō),一個(gè)源(域/端口/協(xié)議三者)無(wú)法獲取另一個(gè)源(origin)的內(nèi)容。因此,即使我們有一個(gè)子域,或者僅僅是另一個(gè)端口,這都是不同的源,彼此無(wú)法相互訪問(wèn)。
這個(gè)規(guī)則還影響其他域的資源。
如果我們使用的是來(lái)自其他域的腳本,并且該腳本中存在 error,那么我們無(wú)法獲取 error 的詳細(xì)信息。
例如,讓我們使用一個(gè)腳本 error.js
,該腳本只包含一個(gè)(錯(cuò)誤)函數(shù)調(diào)用:
// error.js
noSuchFunction();
現(xiàn)在從它所在的同一個(gè)網(wǎng)站加載它:
<script>
window.onerror = function(message, url, line, col, errorObj) {
alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="/article/onload-onerror/crossorigin/error.js"></script>
我們可以看到一個(gè)很好的 error 報(bào)告,就像這樣:
Uncaught ReferenceError: noSuchFunction is not defined
https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1
現(xiàn)在,讓我們從另一個(gè)域中加載相同的腳本:
<script>
window.onerror = function(message, url, line, col, errorObj) {
alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js" rel="external nofollow" rel="external nofollow" ></script>
此報(bào)告與上面那個(gè)示例中的不同,就像這樣:
Script error.
, 0:0
error 的詳細(xì)信息可能因?yàn)g覽器而異,但是原理是相同的:有關(guān)腳本內(nèi)部的任何信息(包括 error 堆棧跟蹤)都被隱藏了。正是因?yàn)樗鼇?lái)自于另一個(gè)域。
為什么我們需要 error 的詳細(xì)信息?
因?yàn)橛泻芏喾?wù)(我們也可以構(gòu)建自己的服務(wù))使用 window.onerror
監(jiān)聽(tīng)全局 error,保存 error 并提供訪問(wèn)和分析 error 的接口。這很好,因?yàn)槲覀兛梢钥吹接捎脩粲|發(fā)的實(shí)際中的 error。但是,如果一個(gè)腳本來(lái)自于另一個(gè)源(origin),那么正如我們剛剛看到的那樣,其中沒(méi)有太多有關(guān) error 的信息。
對(duì)其他類型的資源也執(zhí)行類似的跨源策略(CORS)。
要允許跨源訪問(wèn),<script>
標(biāo)簽需要具有 crossorigin
特性(attribute),并且遠(yuǎn)程服務(wù)器必須提供特殊的 header。
這里有三個(gè)級(jí)別的跨源訪問(wèn):
crossorigin
? 特性 —— 禁止訪問(wèn)。crossorigin="anonymous"
? —— 如果服務(wù)器的響應(yīng)帶有包含 ?*
? 或我們的源(origin)的 header ?Access-Control-Allow-Origin
?,則允許訪問(wèn)。瀏覽器不會(huì)將授權(quán)信息和 cookie 發(fā)送到遠(yuǎn)程服務(wù)器。crossorigin="use-credentials"
? —— 如果服務(wù)器發(fā)送回帶有我們的源的 header ?Access-Control-Allow-Origin
? 和 ?Access-Control-Allow-Credentials: true
?,則允許訪問(wèn)。瀏覽器會(huì)將授權(quán)信息和 cookie 發(fā)送到遠(yuǎn)程服務(wù)器。請(qǐng)注意:
你可以在 Fetch:跨源請(qǐng)求 一章中了解有關(guān)跨源訪問(wèn)的更多信息。這一章描述了用于網(wǎng)絡(luò)請(qǐng)求的
fetch
方法,但策略是完全相同的。
諸如 “cookie” 之類的內(nèi)容超出了本章的范圍,但你可以在 Cookie,document.cookie 一章學(xué)習(xí)它們。
在我們的示例中沒(méi)有任何跨源特性(attribute)。因此,跨源訪問(wèn)被禁止。讓我們來(lái)添加它吧。
我們可以在 "anonymous"
(不會(huì)發(fā)送 cookie,需要一個(gè)服務(wù)器端的 header)和 "use-credentials"
(會(huì)發(fā)送 cookie,需要兩個(gè)服務(wù)器端的 header)之間進(jìn)行選擇。
如果我們不關(guān)心 cookie,那么可以選擇 "anonymous"
:
<script>
window.onerror = function(message, url, line, col, errorObj) {
alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script crossorigin="anonymous" src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js" rel="external nofollow" rel="external nofollow" ></script>
現(xiàn)在,假設(shè)服務(wù)器提供了 Access-Control-Allow-Origin
header,一切都正常。我們有了完整的 error 報(bào)告。
圖片 <img>
,外部樣式,腳本和其他資源都提供了 load
和 error
事件以跟蹤它們的加載:
load
? 在成功加載時(shí)被觸發(fā)。error
? 在加載失敗時(shí)被觸發(fā)。唯一的例外是 <iframe>
:出于歷史原因,不管加載成功還是失敗,即使頁(yè)面沒(méi)有被找到,它都會(huì)觸發(fā) load
事件。
readystatechange
事件也適用于資源,但很少被使用,因?yàn)?nbsp;load/error
事件更簡(jiǎn)單。
通常,圖片在被創(chuàng)建時(shí)才會(huì)被加載。所以,當(dāng)我們向頁(yè)面中添加 <img>
時(shí),用戶不會(huì)立即看到圖片。瀏覽器首先需要加載它。
為了立即顯示一張圖片,我們可以“提前”創(chuàng)建它,像這樣:
let img = document.createElement('img');
img.src = 'my.jpg';
瀏覽器開(kāi)始加載圖片,并將其保存到緩存中。以后,當(dāng)相同圖片出現(xiàn)在文檔中時(shí)(無(wú)論怎樣),它都會(huì)立即顯示。
創(chuàng)建一個(gè)函數(shù) preloadImages(sources, callback)
,來(lái)加載來(lái)自數(shù)組 source
的所有圖片,并在準(zhǔn)備就緒時(shí)運(yùn)行 callback
。
例如,這段代碼將在圖片加載完成后顯示一個(gè) alert
:
function loaded() {
alert("Images loaded")
}
preloadImages(["1.jpg", "2.jpg", "3.jpg"], loaded);
如果出現(xiàn)錯(cuò)誤,函數(shù)應(yīng)該仍假定圖片已經(jīng)“加載完成”。
換句話說(shuō),當(dāng)所有圖片都已加載完成,或出現(xiàn)錯(cuò)誤輸出時(shí),將執(zhí)行 callback
。
例如,當(dāng)我們計(jì)劃顯示一個(gè)包含很多圖片的可滾動(dòng)圖冊(cè),并希望確保所有圖片都已加載完成時(shí),這個(gè)函數(shù)很有用。
在源文檔中,你可以找到指向測(cè)試圖片的鏈接,以及檢查它們是否已加載完成的代碼。它應(yīng)該輸出 300
。
算法:
img
?。onload/onerror
?。onload
? 或 ?onerror
? 被觸發(fā)時(shí),增加計(jì)數(shù)器。callback()
?。Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: