- Загрузка ресурсов: onload и onerror
- Загрузка скриптов
- script.onload
- script.onerror
- Другие ресурсы
- Ошибка в скрипте с другого источника
- Итого
- Задачи
- Загрузите изображения с колбэком
- 5 Ways To Display Dynamic HTML Content In Javascript
- TLDR – QUICK SLIDES
- TABLE OF CONTENTS
- DYNAMIC CONTENT WITH JAVASCRIPT
- 1) CHANGE CONTENTS WITH INNERHTML & OUTERHTML
- 2) CREATE HTML ELEMENT & INSERT
- 3) AJAX LOAD CONTENT
- 4) AJAX LOAD DATA & GENERATE TABLE/LIST
- 5) DYNAMICALLY LOAD CSS FILES
- DOWNLOAD & NOTES
- SUPPORT
- EXAMPLE CODE DOWNLOAD
- EXTRA BITS & LINKS
- THE SUMMARY
- FUNCTIONS & PROPERTIES
- AJAX FETCH
- JSON
- TUTORIAL VIDEO
- INFOGRAPHIC CHEAT SHEET
- THE END
Загрузка ресурсов: onload и onerror
Браузер позволяет отслеживать загрузку сторонних ресурсов: скриптов, ифреймов, изображений и др.
Для этого существуют два события:
Загрузка скриптов
Допустим, нам нужно загрузить сторонний скрипт и вызвать функцию, которая объявлена в этом скрипте.
Мы можем загрузить этот скрипт динамически:
let script = document.createElement('script'); script.src = "my.js"; document.head.append(script);
…Но как нам вызвать функцию, которая объявлена внутри того скрипта? Нам нужно подождать, пока скрипт загрузится, и только потом мы можем её вызвать.
Для наших собственных скриптов мы можем использовать JavaScript-модули, но они не слишком широко распространены в сторонних библиотеках.
script.onload
Главный помощник – это событие load . Оно срабатывает после того, как скрипт был загружен и выполнен.
let script = document.createElement('script'); // мы можем загрузить любой скрипт с любого домена script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js" document.head.append(script); script.onload = function() < // в скрипте создаётся вспомогательная переменная с именем "_" alert(_.VERSION); // отображает версию библиотеки >;
Таким образом, в обработчике onload мы можем использовать переменные, вызывать функции и т.д., которые предоставляет нам сторонний скрипт.
…А что если во время загрузки произошла ошибка? Например, такого скрипта нет (ошибка 404), или сервер был недоступен.
script.onerror
Ошибки, которые возникают во время загрузки скрипта, могут быть отслежены с помощью события error .
Например, давайте запросим скрипт, которого не существует:
let script = document.createElement('script'); script.src = "https://example.com/404.js"; // такого файла не существует document.head.append(script); script.onerror = function() < alert("Ошибка загрузки " + this.src); // Ошибка загрузки https://example.com/404.js >;
Обратите внимание, что мы не можем получить описание HTTP-ошибки. Мы не знаем, была ли это ошибка 404 или 500, или какая-то другая. Знаем только, что во время загрузки произошла ошибка.
Обработчики onload / onerror отслеживают только сам процесс загрузки.
Ошибки обработки и выполнения загруженного скрипта ими не отслеживаются. Чтобы «поймать» ошибки в скрипте, нужно воспользоваться глобальным обработчиком window.onerror .
Другие ресурсы
События load и error также срабатывают и для других ресурсов, а вообще, для любых ресурсов, у которых есть внешний src .
let img = document.createElement('img'); img.src = "https://js.cx/clipart/train.gif"; // (*) img.onload = function() < alert(`Изображение загружено, размеры $x$`); >; img.onerror = function() < alert("Ошибка во время загрузки изображения"); >;
Однако есть некоторые особенности:
- Большинство ресурсов начинают загружаться после их добавления в документ. За исключением тега . Изображения начинают загружаться, когда получают src (*) .
- Для событие load срабатывает по окончании загрузки как в случае успеха, так и в случае ошибки.
Такое поведение сложилось по историческим причинам.
Ошибка в скрипте с другого источника
Есть правило: скрипты с одного сайта не могут получить доступ к содержимому другого сайта. Например, скрипт с https://facebook.com не может прочитать почту пользователя на https://gmail.com .
Или, если быть более точным, один источник (домен/порт/протокол) не может получить доступ к содержимому с другого источника. Даже поддомен или просто другой порт будут считаться разными источниками, не имеющими доступа друг к другу.
Это правило также касается ресурсов с других доменов.
Если мы используем скрипт с другого домена, и в нем имеется ошибка, мы не сможем узнать детали этой ошибки.
Для примера давайте возьмём мини-скрипт error.js , который состоит из одного-единственного вызова функции, которой не существует:
Теперь загрузим этот скрипт с того же сайта, на котором он лежит:
Мы видим нормальный отчёт об ошибке:
Uncaught ReferenceError: noSuchFunction is not defined https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1
А теперь загрузим этот же скрипт с другого домена:
Детали отчёта могут варьироваться в зависимости от браузера, но основная идея остаётся неизменной: любая информация о внутреннем устройстве скрипта, включая стек ошибки, спрятана. Именно потому, что скрипт загружен с другого домена.
Зачем нам могут быть нужны детали ошибки?
Существует много сервисов (и мы можем сделать наш собственный), которые обрабатывают глобальные ошибки при помощи window.onerror , сохраняют отчёт о них и предоставляют доступ к этому отчёту для анализа. Это здорово, потому что мы можем увидеть реальные ошибки, которые случились у наших пользователей. Но если скрипт – с другого домена, то информации об ошибках в нём почти нет, как мы только что видели.
Похожая кросс-доменная политика (CORS) внедрена и в отношении других ресурсов.
Чтобы разрешить кросс-доменный доступ, нам нужно поставить тегу атрибут crossorigin , и, кроме того, удалённый сервер должен поставить специальные заголовки.
Существует три уровня кросс-доменного доступа:
- Атрибут crossorigin отсутствует – доступ запрещён.
- crossorigin=»anonymous» – доступ разрешён, если сервер отвечает с заголовком Access-Control-Allow-Origin со значениями * или наш домен. Браузер не отправляет авторизационную информацию и куки на удалённый сервер.
- crossorigin=»use-credentials» – доступ разрешён, если сервер отвечает с заголовками Access-Control-Allow-Origin со значением наш домен и Access-Control-Allow-Credentials: true . Браузер отправляет авторизационную информацию и куки на удалённый сервер.
Почитать больше о кросс-доменных доступах вы можете в главе Fetch: запросы на другие сайты. Там описан метод fetch для сетевых запросов, но политика там точно такая же.
Такое понятие как «куки» (cookies) не рассматривается в текущей главе, но вы можете почитать о них в главе Куки, document.cookie.
В нашем случае атрибут crossorigin отсутствовал. Поэтому кросс-доменный доступ был запрещён. Давайте добавим его.
Мы можем выбрать «anonymous» (куки не отправляются, требуется один серверный заголовок) или «use-credentials» (куки отправляются, требуются два серверных заголовка) в качестве значения атрибута.
Если куки нас не волнуют, тогда смело выбираем «anonymous» :
Теперь при условии, что сервер предоставил заголовок Access-Control-Allow-Origin , всё хорошо. У нас есть полный отчёт по ошибкам.
Итого
Изображения , внешние стили, скрипты и другие ресурсы предоставляют события load и error для отслеживания загрузки:
Единственное исключение – это : по историческим причинам срабатывает всегда load вне зависимости от того, как завершилась загрузка, даже если страница не была найдена.
Событие readystatechange также работает для ресурсов, но используется редко, потому что события load/error проще в использовании.
Задачи
Загрузите изображения с колбэком
Обычно изображения начинают загружаться в момент их создания. Когда мы добавляем на страницу, пользователь не увидит его тут же. Браузер сначала должен его загрузить.
Чтобы показать изображение сразу, мы можем создать его «заранее»:
let img = document.createElement('img'); img.src = 'my.jpg';
Браузер начнёт загружать изображение и положит его в кеш. Позже, когда такое же изображение появится в документе (не важно как), оно будет показано мгновенно.
Создайте функцию preloadImages(sources, callback) , которая загружает все изображения из массива sources и, когда все они будут загружены, вызывает callback .
В данном примере будет показан alert после загрузки всех изображений.
function loaded() < alert("Изображения загружены") >preloadImages(["1.jpg", "2.jpg", "3.jpg"], loaded);
В случае ошибки функция должна считать изображение «загруженным».
Другими словами, callback выполняется в том случае, когда все изображения либо загружены, либо в процессе их загрузки возникла ошибка.
Такая функция полезна, например, когда нам нужно показать галерею с маленькими скролящимися изображениями, и мы хотим быть уверены, что все из них загружены.
В песочнице подготовлены ссылки к тестовым изображениям, а также код для проверки их загрузки. Код должен выводить 300 .
- Создадим img для каждого ресурса.
- Добавим обработчики onload/onerror для каждого изображения.
- Увеличиваем счётчик при срабатывании onload или onerror .
- Когда значение счётчика равно количеству ресурсов – тогда вызываем callback() .
5 Ways To Display Dynamic HTML Content In Javascript
Welcome to a tutorial on how to display dynamic HTML content in Javascript. Yes, the Stone Age of the Internet is long over, and we now live in an age of non-static HTML pages. Be it refreshing the shopping cart after adding an item, loading more content, or updating a section of the page.
There are a number of ways to dynamically manipulate HTML contents with Javascript:
- Directly change the contents with innerHTML and outerHTML .
- Create new HTML elements and insert them.
- Load and insert HTML content with AJAX.
- Load data with AJAX, and generate a table or list.
- Dynamically load CSS files.
But just how does each method work exactly? Read on for the examples!
TLDR – QUICK SLIDES
TABLE OF CONTENTS
DYNAMIC CONTENT WITH JAVASCRIPT
All right, let us now get into the examples of manipulating dynamic HTML content in Javascript.
1) CHANGE CONTENTS WITH INNERHTML & OUTERHTML
window.addEventListener("load", () => < // (B1) REPLACE THE ENTIRE ELEMENT WITH var first = document.getElementById("first"); first.outerHTML = "FOO BAR!"; // (B2) WILL STILL BE A , BUT CONTENT WILL BE CHANGED. var second = document.getElementById("second"); second.innerHTML = "FOO BAR"; >);
- The innerHTML refers to the contents of the given element.
- The outerHTML refers to the entire element itself.
2) CREATE HTML ELEMENT & INSERT
- Create a new element – var el = document.createElement(«TAG»);
- Set the contents – el.innerHTML = «CONTENT»;
- Append it – document.getElementById(«ID»).appendChild(el);
3) AJAX LOAD CONTENT
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
For you guys who have not heard of AJAX before, it is the abbreviation for “Asynchronous Javascript And XML”. In layman’s terms, loading content and data without refreshing the entire page. Very useful – We can use it to send data to the server, fetch data from the server, or even load more content.
P.S. Take note that AJAX will only work with http:// , not file:// .
4) AJAX LOAD DATA & GENERATE TABLE/LIST
This is a follow-up to the previous AJAX example – Yes, we can parse an array of JSON data from the server, and generate a table or list with it. I will not go through the server-side processing as it is out-of-scope for this tutorial – Read my other guide for PHP JSON if you are interested.
5) DYNAMICALLY LOAD CSS FILES
Remember that we can create HTML tags from earlier? Yes, we can even create tags and insert them into the section – Effectively, dynamically loading CSS files.
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
SUPPORT
600+ free tutorials & projects on Code Boxx and still growing. I insist on not turning Code Boxx into a «paid scripts and courses» business, so every little bit of support helps.
EXAMPLE CODE DOWNLOAD
Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
EXTRA BITS & LINKS
That’s it for all the examples, and here are some small extras that may be useful.
THE SUMMARY
FUNCTIONS & PROPERTIES
AJAX FETCH
fetch("URL") .then(res => res.text()) // read server response as text .then(response => < console.log(response); // whatever the server response is >);
P.S. If you need to fetch from another website (cross-domain) – It is possible, but some Cross-Origin Resource Sharing (CORS) settings need to be done. Check out my other fetch CORS tutorial.
JSON
TUTORIAL VIDEO
INFOGRAPHIC CHEAT SHEET
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you to create a better dynamic HTML page, and if you have anything to share with this guide, please feel free to comment below. Good luck and happy coding!