Il browser permette di tracciare il caricamento di risorse esterne: script, iframe, immagini e così via.
Esistono 2 eventi per tracciare il caricamento:
onload– caricato con successo,onerror– si è verificato un errore.
Caricamento di uno script
Diciamo che abbiamo necessità di caricare uno script di terze parti e chiamare una funzione che appartiene a questo script.
Possiamo caricarlo dinamicamente, in questo modo:
let script = document.createElement('script'); script.src = "my.js"; document.head.append(script); …Ma come possiamo eseguire la funzione dichiarata all’interno di quello script? Dobbiamo attendere la fine del caricamento dello script e successivamente chiamare la funzione.
Per i nostri script dovremmo utilizzare i moduli JavaScript in questo caso, ma non sono largamente adottati dalle librerie di terze parti.
script.onload
Il principale helper è l’evento load. Si innesca dopo che lo script è stato caricato ed eseguito.
Per esempio:
let script = document.createElement('script'); // si può caricare qualunque script, da qualunque dominio script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js" document.head.append(script); script.onload = function() { // lo script crea una funzione helper "_" alert(_); // la funzione è disponibile }; Quindi nell’evento onload possiamo utilizzare le variabili dello script, eseguire funzioni, ecc.
script.onerror
Gli errori che si verificano durante il caricamento dello script possono essere tracciati tramite l’evento error.
! script.onerror = function() { alert("Caricamento fallito " + this.src); // Error loading https://example.com/404.js }; /!
Notate bene che in questo punto non possiamo ottenere i dettagli dell'errore HTTP. Non sappiamo se è un errore 404 o 500 o qualcos'altro. ```warn Gli eventi `onload`/`onerror` tracciano solo il caricamento stesso. Gli eventi load e error funzionano anche per le altre risorse, praticamente per qualunque risorsa che ha un src esterno.
Per esempio:
let img = document.createElement('img'); img.src = "https://js.cx/clipart/train.gif"; // (*) img.onload = function() { alert(`Immagine caricata, dimensione ${img.width}x${img.height}`); }; img.onerror = function() { alert("Si è verificato un errore durante il caricamento dell'immagine"); }; Ci sono alcune note però:
- Per gli
<iframe>, l’eventoiframe.onloadsi aziona quando il caricamento dell’ iframe è terminato, sia in caso di successo che in caso di errore.
C’è una regola: gli script di un sito non possono accedere ai contenuti di un altro sito. Quindi, per esempio, uno script di https://facebook.com non può leggere la casella di posta dell’utente di https://gmail.com.
Per essere più precisi, un’origine (tripletta dominio/porta/protocollo) non può accedere al contenuto di un’altra. Quindi se abbiamo un sottodominio, o anche solo un’altra porta, questo sarà un’origine differente e quindi non hanno accesso l’uno con l’altro.
Questa regola interessa anche le risorse di altri domini.
Se stiamo utilizzando uno script di un altro dominio e c’è un errore, non possiamo ottenere i dettagli di quell’errore.
Per esempio, prendiamo lo script error.js, che consiste in una singola chiamata ad una funzione (sbagliata):
// 📁 error.js noSuchFunction(); Ora caricatela dallo stesso sito su cui è situato lo script:
<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> Vedremo il report dell’errore, come questo:
Uncaught ReferenceError: noSuchFunction is not defined https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1 Ora carichiamo lo stesso script da un altro dominio:
<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> Il report di errore è diverso rispetto a quello precedente, come questo:
Script error. , 0:0 Ci sono molti servizi (e possiamo anche sviluppare il nostro) che stanno in ascolto sugli errori globali, utilizzando window.onerror, salvano gli errori e forniscono un interfaccia per accedere ed analizzarli. Fantastico, possiamo vedere i veri errori, scaturiti dai nostri utenti. Ma se uno script è caricato da un altro dominio non avremo nessuna informazioni sull’errore, come abbiamo appena visto.
Una policy cross-origin (CORS) simile viene applicata anche per altri tipi di risorse.
Per consentire l’accesso cross-origin il tag <script> deve avere l’attributo crossorigin e il server remoto deve fornire degli header speciali.
Ci sono tre livelli di accesso cross-origin:
- Attributo
crossoriginnon presente – accesso vietato. crossorigin="anonymous"– accesso consentito se il server risponde con l’headerAccess-Control-Allow-Origincon il valore*o il nome della nostra origin (dominio). Il browser non manda dati e cookie sull’autenticazione al server remoto.crossorigin="use-credentials"– accesso consentito se il server manda indietro l’headerAccess-Control-Allow-Origincon la nostra origine (dominio) eAccess-Control-Allow-Credentials: true. Il browser manda i dati e i cookie sull’autenticazione al server remoto.
Puoi approfondire l’accesso cross-origin nel capitolo Fetch: Cross-Origin Requests. Descrive il metodo fetch per le richieste di rete, ma la policy è esattamente la stessa.
Ad esempio i “cookies” sono un argomento fuori dal nostro attuale ambito, ma puoi leggere informazioni a proposito nel capitolo Cookies, document.cookie.
Nel nostro caso non avevamo nessun attributo crossorigin, quindi l’accesso era vietato. Aggiungiamo l’attributo ora.
Possiamo scegliere tra "anonymous" (non vengono mandati cookie, è necessario un header lato server) e "use-credentials" (manda i cookie, sono necessari 2 header lato server).
Se non ci interessano i cookie allora "anonymous" è la scelta giusta:
<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> Ora, supponendo che il server fornisca l’header Access-Control-Allow-Origin, riusciamo ad avere il report completo dell’errore.
Riepilogo
Immagini <img>, fogli di stile esterni, script e altre risorse forniscono gli eventi load e error per tracciare i loro caricamento:
loadsi aziona se il caricamento va a buon fine,errorsi azione se si verifica un errore durante il caricamento.
L’unica eccezione è <iframe>: per ragioni storiche scatta sempre l’evento load, per qualunque esito del caricamento, anche se la pagina non è stata trovata.
Possiamo monitorare il caricamento delle risorse anche tramite l’evento readystatechange, ma è poco utilizzato, perché gli eventi load/error sono più semplici.
Commenti
<code>, per molte righe – includile nel tag<pre>, per più di 10 righe – utilizza una sandbox (plnkr, jsbin, codepen…)