Проблема с new URL(), и как URL.parse() её решает
Проблема с new URL()
Слово «new» в строке new URL()
указывает на то, что он используется как конструктор: вызывая его, создаётся новый экземпляр URL. Однако, если передать неверно сформированный URL, который он не сможет разобрать, он выбросит ошибку. Поскольку он выдаёт ошибку, необходимо написать код для её обработки.
Если этого не сделать, то выброшенная ошибка не будет обработана, и JS перестанет выполняться. Следующий код выглядит отлично, но если urlstring
неправильно сформирована, он остановит выполнение:
const urlstring = "this is not a URL";
const not_a_url = new URL(urlstring);
// Uncaught TypeError: URL constructor: "this is not a URL" is not a valid URL.
Поэтому необходимо обернуть его в try
...catch
, чтобы ошибка была поймана.
const urlstring = "this is not a URL";
let not_a_url;
try {
not_a_url = new URL(urlstring);
} catch {
// мы поймаем и проигнорируем ошибку
// not_a_url уже undefined, поэтому не нужно ничего делать.
}
Это намного больше строк кода, больше визуального шума и значит, что придётся изменить not_a_url
с const
на let
, чтобы получить возможность перезаписи. В итоге поток управления приложением становится более сложным.
Делаем немного лучше
Недавно в URL API была добавлена функция URL.canParse()
, возвращающая true
, если URL-адрес можно разобрать.
Она доступна для кросс-браузерного использования только с декабря 2023 года, поэтому, возможно, её рано повсеместно использовать, но она делает код более читабельным.
Вместо того чтобы пытаться поймать ошибку, сначала можно проверить, можно ли разобрать URL, прежде чем разбирать его, и сделаем это одной строкой:
const urlstring = "this is not a URL";
const not_a_url = URL.canParse(urlstring) && new URL(urlstring);
// not_a_url = false
Таким образом, not_a_url
снова становится const
, что, безусловно, проще для понимания.
Жалуемся
Вместо проявления конструктивности и написания собственной маленькой функции для абстрагирования этих try
...catch
или canParse
от своей обычной кодовой базы, я решил поступить правильно и пожаловаться в Twitter:
Заставить new URL() выбрасывать ошибку, когда передаёте ей недопустимый URL, было ужасным выбором API.
Немного позже Anne van Kesteren ответила ссылкой на GitHub issue, в нём обсуждалось добавление функции «parse» к URL, которая бы не выбрасывала ошибку.
Anne добавила этот issue в 2018 году, но мой твит возобновил интерес. Немного позже Anne добавила URL.parse()
в спецификацию, и ошибки в реализации были зафиксированы для всех браузерных движков.
Anne самостоятельно реализовала его в WebKit, и он также будет поставляться в Chromium 126 и Firefox 126.
Использование URL.parse()
С помощью URL.parse()
можно вернуться к исходному примеру, приведённому выше, и сохранить поток управления как можно более простым:
const urlstring = "this is not a URL";
const not_a_url = URL.parse(urlstring);
// not_a_url = null
Браузеры с этой функцией появятся в ближайшие несколько месяцев (Firefox — в мае, Chrome — в июне, пока не удалось выяснить, когда появится Safari), так что придётся немного подождать, прежде чем использовать эту функцию. Не могу дождаться, когда избавлюсь от всех своих try
...catch
вызовов!