到目前为止,一切似乎都运转良好。我们的应用程序从外部页面获取标题,在本地存储链接,在页面上呈现链接,并在需要时从页面中清除它们。
但是如果出了什么问题呢?如果我们给它一个无效链接会发生什么?如果请求超时会发生什么?我们将处理两种最可能的情况:当用户提供一个URL,该URL通过了输入字段的验证检查,但实际上并不有效;当URL有效,但服务器返回400或500级错误时。
我们添加的第一件事是处理任何错误的能力。我们需要提供一个捕获异常的方法,当出现错误的时候,进行调用。我们在这个事件中定义了另一个帮助方法。
图2.31 显示错误消息: ./app/renderer.js
const handleError = (error, url) => { +如果获取链接失败, errorMessage.innerHTML = ` |则设置错误消息元素的内容 There was an issue adding "${url}": ${error.message} | + `.trim(); <----+ | setTimeout(() => errorMessage.innerText = null, 5000); <----+5秒后清除错误消息 } +
我们可以把它加到链上。我们使用另一个匿名函数传递带有错误消息的URL。这主要是为了提供更好的错误消息。如果不希望在错误消息中包含URL,则没有必要这样做。
图2.32 在获取、解析和呈现链接时捕获错误: ./app/renderer.js
fetch(url) .then(response => response.text()) .then(parseResponse) + .then(findTitle) | .then(title => storeLink(title, url)) |如果此处理链中的任何错误拒绝或抛出错误 .then(clearForm) |则捕获错误并将其显示在UI中 .then(renderLinks) | .catch(error => handleError(error, url)); <--+
我们还在前面添加了一个步骤,用于检查请求是否成功。如果是,它将请求传递给处理链中的下一个操作。如果没有成功,那么我们将抛出一个错误,这将绕过处理链中的其余操作,并直接跳到handleError()步骤。这里有一个我没有处理的异常情况:如果Fetch API不能建立网络连接,那么它返回的承诺将被完全拒绝。我把它作为练习留给读者来处理,因为我们在这本书中有很多内容要讲,而且页数有限。响应。如果状态码在400或500范围内,response.ok将为false。
图2.33 验证来自远程服务器的响应: ./app/renderer.js
+ |如果响应成功,则将其 const validateResponse = (response) => { |传递给下一个处理链 if (response.ok) { return response; } <-----+ throw new Error(`Status code of ${response.status} + ${response.statusText}`); <-----+ } |如果请求收到400或500系列响应 +则引发错误。
如果没有错误,此代码将传递响应对象。但是,如果出现错误,它会抛出一个错误,handleError()会捕捉到这个错误并相应地进行处理。
图2.34 在处理链中添加validateResponse(): ./app/renderer.js
fetch(url) .then(validateResponse) .then(response => response.text()) .then(parseResponse) .then(findTitle) .then(title => storeLink(title, url)) .then(clearForm) .then(renderLinks) .catch(error => handleError(error, url));一个意想不到的错误
我们还没有走出困境——如果一切顺利的话,我们还有一个问题。如果单击应用程序中的一个链接会发生什么?也许并不奇怪,它指向了那个链接。我们的Electron应用程序的Chromium部分认为它是一个web浏览器,所以它做了web浏览器最擅长的事情—它进入页面。
只是我们的应用程序并不是真正的web浏览器。它缺少后退按钮或位置栏等重要功能。如果我们点击应用程序中的任何链接,我们就会几乎被困在那里。我们唯一的选择是关闭应用程序,重新开始。
解决方案是在真正的浏览器中打开链接。但这引出了一个问题,哪个浏览器?我们如何知道用户将什么设置为默认浏览器?我们当然不想做任何侥幸的猜测,因为我们不知道用户安装了什么浏览器,而且没有人喜欢看到错误的应用程序仅仅因为他们点击了一个链接就开始打开。 Electron随shell模块一起载运,shell模块提供了一些与之相关的功能,高级桌面集成。shell模块可以询问用户的操作系统他们更喜欢哪个浏览器,并将URL传递给要打开的浏览器。让我们从引入Electron开始,并在app/renderer.js的顶部存储对其shell模块的引用。
列表2.35 引用Electron的shell 模块: ./app/renderer.js
const {shell} = require('electron');