AJAX请求失败时.fail()方法未执行,求问题排查思路
.fail()方法不生效? 嘿,这个问题我太熟悉了!咱们先直击核心:JSONP 不是真正的 AJAX 请求,它的工作机制导致 jQuery 的.fail()回调根本没法捕获加载失败的情况。咱们一步步拆解原因,再给你可行的解决方案:
核心原因:JSONP 的工作原理限制
JSONP 是通过动态插入 <script> 标签来加载远程脚本,而不是使用传统的 XMLHttpRequest(也就是咱们常说的AJAX)。浏览器对于 <script> 标签的加载失败,没有提供可以被 jQuery 监听的错误事件——所以哪怕请求超时、API 挂了,.fail() 也不会被触发。这就是你遇到的问题的根源。
另外还要提一句:你设置的 quoteRequestTimeout 定时器和 .fail() 是完全独立的,jQuery 的 timeout 参数对 JSONP 请求也完全无效,因为它不是XHR请求。
可行的解决方案
既然 .fail() 用不了,咱们得换个思路来处理错误:
1. 用定时器 + 成功标记模拟错误处理
这是目前处理JSONP错误最靠谱的方式。我们在请求开始时设置一个标记,请求成功时把标记置为true,如果定时器触发时标记还是false,就判定请求失败:
var requestSucceeded = false; var quoteRequestTimeout = setTimeout(function(){ if (!requestSucceeded) { // 这里统一处理请求失败的逻辑 if ($.isEmptyObject(backupQuote)){ $quoteText.text('Failed to get a new quote'); $author.text(''); } else { $quoteFail.text('Failed to get a new quote'); $quoteText.text(backupQuote.quoteText); $author.text(backupQuote.quoteAuthor); } } }, 8000); $.ajax({ url: "https://api.forismatic.com/api/1.0/", jsonp: "jsonp", dataType: "jsonp", data: { method: "getQuote", lang: "en", format: "jsonp" }, cache: false }) .done(function(data, status, jqXHR) { requestSucceeded = true; clearTimeout(quoteRequestTimeout); // 你的成功逻辑 console.log(data); $quoteText.text(data.quoteText); $author.text(data.quoteAuthor); backupQuote = { quoteText: data.quoteText, quoteAuthor: data.quoteAuthor }; $quoteFail.text(''); });
2. 在.done()里检查返回数据的有效性
有时候API不会直接失败,而是返回一个包含错误信息的合法JSONP响应。这时候.done()会被触发,但数据是无效的。你可以在成功回调里加一层校验:
.done(function(data) { // 检查返回的名言数据是否有效 if (!data.quoteText || !data.quoteAuthor) { // 触发失败处理逻辑 if ($.isEmptyObject(backupQuote)){ $quoteText.text('Failed to get a new quote'); $author.text(''); } else { $quoteFail.text('Failed to get a new quote'); $quoteText.text(backupQuote.quoteText); $author.text(backupQuote.quoteAuthor); } return; } // 正常处理有效数据 console.log(data); $quoteText.text(data.quoteText); $author.text(data.quoteAuthor); backupQuote = { quoteText: data.quoteText, quoteAuthor: data.quoteAuthor }; $quoteFail.text(''); clearTimeout(quoteRequestTimeout); });
3. 改用支持CORS的API(如果可行)
如果目标API支持CORS(跨域资源共享),你可以把dataType改成json,这样就变成了真正的AJAX请求,.fail()就能正常捕获错误了。不过Forismatic的API主要是为JSONP设计的,这个方案可能不适用,但可以作为备选思路。
总结
JSONP的局限性决定了它没法用常规的.fail()处理错误,所以定时器+成功标记的方式是目前最实用的解决方案。你已经有了超时逻辑,只需要加上成功标记的判断就能完善错误处理啦!
内容的提问来源于stack exchange,提问作者Oxi_Bo

