
如今,很少有人记得没有单个XHR请求就可以运行Web应用程序。 AJAX(异步Javascript和XML)提供了一个很酷的功能-加载数据而无需重新加载页面。 这个概念是大多数现代SPA的基础。
但是,仅此而已,您必须付出一切。 AJAX概念似乎非常简单,但是即使在从服务器请求数据的级别上,您也会遇到很多问题。
首先,让我们用AJAX编写最简单的SPA应用程序:
initApp(); function initApp() { document.body.innerHTML = ` <h3>Employees list</h3> <ul id="employees-list"></ul> <button id="load-employees">Load employee</button> `; document.getElementById('load-employees').addEventListener('click', loadEmployee); } function loadEmployee() { fetch('http://dummy.restapiexample.com/api/v1/employee/1') .then(res => res.json()).then(({employee_name}) => addEmployee(employee_name)); } function addEmployee(employeeName) { const employeeElement = document.createElement('li'); employeeElement.innerText = employeeName; document.getElementById('employees-list').appendChild(employeeElement); }
一切都非常简单:当您单击该按钮时,我们会从服务器请求数据,并在收到数据后将其添加到列表中。
就像我说的那样,在此阶段可能会出错,并且为了更深入地讨论这个话题,我们将首先分析一些理论。
建立容错接口的两种原理

优雅降级
这是界面设计理念,其中最初为用户提供了尽可能多的功能。 并且只有在系统任何部分发生故障的情况下,取决于它的功能才被禁用。 听起来很复杂,但是下面我们将通过一个示例进行分析-它将更加清晰。
渐进增强
有一种替代/并行的哲学-渐进增强。 在这种情况下,移动是另一种方式:最初,向用户提供了最少(或平均)的功能集。 为了初始化其余部分,首先要检查系统各部分工作所需的支持。
通常,在基于浏览器的应用程序上下文中谈论
适度降级和逐步增强时,它们的意思是跨浏览器的兼容性或适应性。 有一个流行的示例解释了这些概念。 假设您的应用程序具有打印页功能,并且如果执行此操作:
<body> <a href="javascript:window.print()" id="print-btn">Print</a> <script> const printButton = document.getElementById('print-btn'); if (printButton && typeof window.print !== 'function') { printButton.parentNode.appendChild(document.createTextNode(' ')); printButton.parentNode.removeChild(printButton); } </script> </body>
那么这是
正常的降级 ,因为您立即显示了“打印”按钮,但是当您意识到浏览器不支持打印时,您就删除了该功能。
PS:在原始示例中,使用noscript标记来演示
优美的降级效果 ,但是在我看来,这已经过时了。
如果您这样做:
if(typeof window.print === 'function') { const printButton = document.createElement('a'); printButton.innerText = 'Print'; printButton.addEventListener('click', () => window.print()); document.body.appendChild(printButton); }
这是一项
渐进的增强功能 ,因为首先检查所需API的支持,然后再添加功能。
这些示例演示了容错接口设计理念的最原始应用。
返回
AJAX和
HTTP请求 。
AJAX可能会出什么问题?
意外的HTTP状态代码

最简单的情况是服务器返回您期望的错误状态代码(例如500)。这是常见的情况,您可能有一些处理它的工具。 例如,向用户显示通知“发生服务器错误”。 这显然是退化,但是它有多优雅? 可以在这里应用渐进增强吗? 不,这绝对不是逐步增强的地方-功能已经降级。 您只能很好地克服这一麻烦:
- 找出这种情况通常发生在客户端,以防止将来发生。 为此,通常使用错误记录器,例如sentry.io 。
- 如果可能的话,缓存接收到的数据。 如果已经有一个类似请求的调用并且您缓存了数据,那太酷了。 在这种情况下,即使您从服务器收到意外的状态代码,也可以显示界面,尽管不会显示最新数据。
- 稍后尝试重试该请求。 也许这是服务器暂时崩溃,几秒钟后它将“释放”。 您可以自动发出第二个请求,也可以将此选项提供给用户。
- 不要阻塞应用程序的其余部分。 如果在调用HTTP请求之前显示了微调器或骨架,则不要忘记在请求完成后(无论成功与否)将其隐藏。 这看起来似乎很明显,但是我经常遇到这种情况。
- 通常,可能会有许多意外的状态代码,例如,当用户会话过期并且服务器以代码403响应时。对于此错误,需要使用单独的处理程序来重新发出会话令牌或发送用户进行授权。 故障转移应用程序必须具有用于所有可能的服务器响应的处理程序。
无效的答案

永远不要相信后端! 服务器可以使用代码200进行响应,但是在响应的主体中,它将返回所需的错误数据。 在这种情况下,您可以执行与意外状态代码相同的操作,但是困难在于确定答案确实无效。
如果您使用打字稿撰写,那么对您来说,有个很酷的工具
-typescript-json-schema 。 使用它,您可以从打字稿接口生成json方案,并在运行时使用它们验证数据。
长答案

这是很少有人期望的打击。 如果我们记得错误或什至无效的响应数据,我们很少记得超时。 罪魁祸首可能不仅是服务器应用程序,甚至是互联网提供商或客户端设备。
不要忘记它,最好通知用户该请求的时间比平常长,而不是让用户在屏幕上留下一个旋转的圆圈。 当为执行请求分配的时间到期时,您将经历与前两种情况类似的场景。
缺乏互联网

得知Google文档具有离线模式,我印象深刻。 当我决定在没有互联网的飞机上写完一篇文章时,这对我很有帮助。
当然,应用程序是不同的,没有互联网,其中许多应用程序实际上是无用的。 但是即使在这些应用程序中,您也可以在没有连接的情况下处理该情况并显示一条信息丰富的消息(尽管我也喜欢在“ Chrome”中播放暴龙)。
此外,您可以收听
连接/断开Internet连接的事件 。 并且,例如,在窗口上的在线事件期间自动重新加载数据。
容错界面-这并不容易
总的来说,调用HTTP请求时必须执行的操作列表:
- 记录错误。
- 缓存数据并使用它。
- 重复失败的请求。
- 不要阻塞接口。
- 处理所有可能的服务器响应。
- 验证服务器响应。
- 设置超时时间。
- 离线模式(缺少互联网)。
起初看起来微不足道的东西变成了带有许多问题的整体哲学。 当然,这不是标头广告。 但是,如果您的应用程序已经达到很高的成熟度,并且您想要创建一个真正高质量的界面,那么这就是值得开发的方向。
本文的目的是讨论使用HTTP请求时可能出现的问题,而不是特定的解决方案。 如今,有许多旨在解决这些问题的库和框架,例如Angular中的HTTP拦截器。
知道可能的问题后,在Internet上为他们找到解决方案会容易得多。