原作者:Kilian Valkhof
原E文连接:The problem with new URL(), and how URL.parse() fixes that
The problem with new URL(), and how URL.parse() fixes that
As someone building a browser I need to parse a lot of URLs. Partially to validate them, but also to normalize them or get specific parts out of the URL. The URL API in browsers lets you do that, but it’s ergonomics aren’t ideal.
作为一名浏览器开发者,我需要解析很多URL。部分原因是验证它们,但同时也为了规范化它们或者从URL中提取特定的部分。浏览器中的URL API允许你这么做,但其操作并不理想。
The problem with new URL()
The “new” in front of new URL() indicates that it’s used as a constructor: calling it creates a new URL instance for you. When you give it a malformed URL however, one that it can’t parse, it throws an error. Because it throws an error, you need to write code to handle that error.new URL()中的“new”表明它被用作构造函数:调用它会为你创建一个新的URL实例。然而,当你给它一个格式错误的URL时,一个它无法解析的URL,它会抛出一个错误。因为它会抛出错误,你需要编写代码来处理这个错误。
If you don’t do that, The thrown error won’t get handled and your JS stops being executed. The following code looks great but if urlstring is malformed, it will stop execution:
如果你不这样做,抛出的错误将无法处理,你的JavaScript代码也将停止执行。以下代码看起来不错,但如果urlstring格式不正确,它将停止执行:
const urlstring = "this is not a URL";
const not_a_url = new URL(urlstring);
So you'll want to wrap it in a try...catch so that the error is caught.
所以你可能会想要将它包裹在try...catch中,以便捕获错误。
const urlstring = "this is not a URL";
let not_a_url;
try {
not_a_url = new URL(urlstring);
} catch {
// not_a_url is already undefined so no need to actually do anything.
}
That's a lot more lines of code, has more visual noise and it means you have to change not_a_url from a const to a let to be able to overwrite it. The control flow of the application ends up being more complex.
这需要更多行的代码,视觉上更嘈杂,而且意味着你必须将not_a_url从const改为let以便能够覆盖它。应用程序的控制流变得更复杂。
Making it slightly better
A recent addition to the URL api is URL.canParse(), a function that returns true if the URL is a parseable URL.URL API最近新增了一个功能,即URL.canParse(),如果URL是一个可解析的URL,这个函数会返回true。
It's only been available cross-browser since December 2023 so it might be a little too early for general use, but it does make the code more readable.
这个api需要在2023年12月以后,才能在各个浏览器中使用。所以现在使用可能还为时过早,但它确实使代码更易读。
Instead of trying and catching the error, we can first check if the URL is parseable before parsing it, and we can do that inline:
我们可以在解析URL之前先检查它是否可解析,而不是尝试并捕获错误,而且我们可以内联地做到这一点:
const urlstring = "this is not a URL";
const not_a_url = URL.canParse(urlstring) && new URL(urlstring);
This makes not_a_url a const again, and is definitely easier to understand.
这使得not_a_url再次成为一个const,并且绝对更容易理解。
Complaining
Rather than being constructive and writing my own little function to abstract that try...catch or canParse away from my regular code base, I decided to do the right thing and complain on Twitter:
Making new URL() throw when you give it an invalid URL was a terrible API choice.
使用try...catch或者canParse确实能解决问题,有创造性,但与其让这样的代码出现在我的代码库中,我还是决定做更正确的事情,并且在Twitter上提了异议:
当你给new URL()一个无效的URL时,它会抛出错误,这是一个糟糕的API选择。
Not much later Anne van Kesteren replied with a link to a GitHub issue discussing the addition of a "parse" function to URL that would not throw.
不久之后,Anne van Kesteren回复了一条链接,链接到一个GitHub问题,讨论向URL添加一个不会抛出错误的“parse”函数。
Anne added that issue in 2018 but my tweet renewed interest. Not much later, Anne added URL.parse() to the spec and implementation bugs were filed for all browser engines.
Anne在2018年添加了那个问题(issue),但我的推文重新引起了人们的兴趣。不久之后,Anne将URL.parse()添加到规范中,并为所有浏览器引擎提交了报错的实现(译者注:当遇到无效URL时实现报错逻辑)。
Anne himself implemented it in WebKit and it's also going to ship in Chromium 126 and Firefox 126.
Anne本人在WebKit中实现了它,并且将会在Chromium 126和Firefox 126中发布。
Using URL.parse()
With URL.parse we can go back to that original example all the way up top, and keep our control flow as simple as possible:
有了URL.parse,我们可以回到最上面的那个原始示例,并尽可能保持控制流的简单:
const urlstring = "this is not a URL";
const not_a_url = URL.parse(urlstring);
The browsers with this feature will ship in the next few months (Firefox in May, Chrome in June, I've not been able to figure out when Safari will) so you'll have to wait a little before using it but I can't wait to get rid of all my try..catch calls!
支持此功能的浏览器将在未来几个月内发布(Firefox在五月,Chrome在六月,我还没弄清楚Safari何时会发布),所以你还得等一等才能使用它,但我迫不及待想要摆脱所有的try..catch调用了!