<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JavaScript 頁(yè)面資源加載方法onload,onerror總結(jié)

          共 6449字,需瀏覽 13分鐘

           ·

          2021-03-13 06:15


          資源加載:onload,onerror

          瀏覽器允許我們跟蹤外部資源的加載 —— 腳本,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)用它。

          對(duì)于我們自己的腳本,可以使用 JavaScript module,但是它們并未被廣泛應(yīng)用于第三方庫(kù)。

          script.onload

          我們的得力助手是 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ī)(不可用)。

          script.onerror

          發(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 全局處理程序。

          其他資源

          loaderror 事件也適用于其他資源,基本上(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):

          • 大多數(shù)資源在被添加到文檔中后,便開(kāi)始加載。但是 <img> 是個(gè)例外。它要等到獲得 src (*) 后才開(kāi)始加載。
          • 對(duì)于 <iframe> 來(lái)說(shuō),iframe 加載完成時(shí)會(huì)觸發(fā) iframe.onload 事件,無(wú)論是成功加載還是出現(xiàn) error。

          這是出于歷史原因。

          跨源策略

          這里有一條規(guī)則:來(lái)自一個(gè)網(wǎng)站的腳本無(wú)法訪(fǎng)問(wèn)其他網(wǎng)站的內(nèi)容。例如,位于 https://facebook.com 的腳本無(wú)法讀取位于 https://gmail.com 的用戶(hù)郵箱。

          或者,更確切地說(shuō),一個(gè)源(域/端口/協(xié)議三者)無(wú)法獲取另一個(gè)源(origin)的內(nèi)容。因此,即使我們有一個(gè)子域,或者僅僅是另一個(gè)端口,這都是不同的源,彼此無(wú)法相互訪(fǎng)問(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"></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 并提供訪(fǎng)問(wèn)和分析 error 的接口。這很好,因?yàn)槲覀兛梢钥吹接捎脩?hù)觸發(fā)的實(shí)際中的 error。但是,如果一個(gè)腳本來(lái)自于另一個(gè)源(origin),那么正如我們剛剛看到的那樣,其中沒(méi)有太多有關(guān) error 的信息。

          對(duì)其他類(lèi)型的資源也執(zhí)行類(lèi)似的跨源策略(CORS)。

          要允許跨源訪(fǎng)問(wèn),<script> 標(biāo)簽需要具有 crossorigin 特性(attribute),并且遠(yuǎn)程服務(wù)器必須提供特殊的 header。

          這里有三個(gè)級(jí)別的跨源訪(fǎng)問(wèn):

          1. 無(wú) crossorigin 特性 —— 禁止訪(fǎng)問(wèn)。
          2. crossorigin="anonymous" —— 如果服務(wù)器的響應(yīng)帶有包含 * 或我們的源(origin)的 header Access-Control-Allow-Origin,則允許訪(fǎng)問(wèn)。瀏覽器不會(huì)將授權(quán)信息和 cookie 發(fā)送到遠(yuǎn)程服務(wù)器。
          3. crossorigin="use-credentials" —— 如果服務(wù)器發(fā)送回帶有我們的源的 header Access-Control-Allow-OriginAccess-Control-Allow-Credentials: true,則允許訪(fǎng)問(wèn)。瀏覽器會(huì)將授權(quán)信息和 cookie 發(fā)送到遠(yuǎn)程服務(wù)器。

          你可以在 Fetch:跨源請(qǐng)求 一章中了解有關(guān)跨源訪(fǎng)問(wèn)的更多信息。這一章描述了用于網(wǎng)絡(luò)請(qǐng)求的 fetch 方法,但策略是完全相同的。

          諸如 "cookie" 之類(lèi)的內(nèi)容超出了本章的范圍,但你可以在 Cookie,document.cookie 一章學(xué)習(xí)它們。

          在我們的示例中沒(méi)有任何跨源特性(attribute)。因此,跨源訪(fǎng)問(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"></script>

          現(xiàn)在,假設(shè)服務(wù)器提供了 Access-Control-Allow-Origin header,一切都正常。我們有了完整的 error 報(bào)告。

          總結(jié)

          圖片 <img>,外部樣式,腳本和其他資源都提供了 loaderror 事件以跟蹤它們的加載:

          • load 在成功加載時(shí)被觸發(fā)。
          • error 在加載失敗時(shí)被觸發(fā)。

          唯一的例外是 <iframe>:出于歷史原因,不管加載成功還是失敗,即使頁(yè)面沒(méi)有被找到,它都會(huì)觸發(fā) load 事件。

          readystatechange 事件也適用于資源,但很少被使用,因?yàn)?load/error 事件更簡(jiǎn)單。

          作業(yè)題

          先自己做題目再看答案。

          使用回調(diào)函數(shù)加載圖片

          重要程度:????????

          通常,圖片在被創(chuàng)建時(shí)才會(huì)被加載。所以,當(dāng)我們向頁(yè)面中添加 <img> 時(shí),用戶(hù)不會(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)“加載完成”。

          換句話(huà)說(shuō),當(dāng)所有圖片都已加載完成,或出現(xiàn)錯(cuò)誤輸出時(shí),將執(zhí)行 callback。

          例如,當(dāng)我們計(jì)劃顯示一個(gè)包含很多圖片的可滾動(dòng)圖冊(cè),并希望確保所有圖片都已加載完成時(shí),這個(gè)函數(shù)很有用。

          在源文檔中,你可以找到指向測(cè)試圖片的鏈接,以及檢查它們是否已加載完成的代碼。它應(yīng)該輸出 300

          答案:

          1. 為每個(gè)資源創(chuàng)建 img。
          2. 為每個(gè)圖片添加 onload/onerror。
          3. onloadonerror 被觸發(fā)時(shí),增加計(jì)數(shù)器。
          4. 當(dāng)計(jì)數(shù)器值等于資源值時(shí) —— 我們完成了:callback()。
          function preloadImages(sources, callback{
            let counter = 0;

            function onLoad({
              counter++;
              if (counter == sources.length) callback();
            }

            for(let source of sources) {
              let img = document.createElement('img');
              img.onload = img.onerror = onLoad;
              img.src = source;
            }
          }

          現(xiàn)代 JavaScript 教程:開(kāi)源的現(xiàn)代 JavaScript 從入門(mén)到進(jìn)階的優(yōu)質(zhì)教程。React 官方文檔推薦,與 MDN 并列的 JavaScript 學(xué)習(xí)教程。

          在線(xiàn)免費(fèi)閱讀:https://zh.javascript.info





          最后


          • 歡迎加我微信(winty230),拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專(zhuān)業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧
          瀏覽 64
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天堂网在线视频 | 日本亚欧高清视频 | 黄色操逼小视频国产无码 | 一级黄片毛片在线播放 | 久久久成人午夜无码影院 |