我有一段代码:
update
在我的控制台中,我得到了
function backgroundReadFile(url, callback) {
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.addEventListener("load", function() {
if (req.status < 400)
callback(req.responseText);
});
req.send(null);
}
try {
backgroundReadFile("example/data.txt", function(text) {
if (text != "expected")
throw new Error("That was unexpected");
});
} catch (e) {
console.log("Hello from the catch block");
}
这很好。但是,我被告知:
在代码中,异常不会被捕获,因为 致电
Error: That was unexpected (line 13)
立即返回。然后控制离开backgroundReadFile
块,直到它才会调用它给出的函数 后面。
问题是:为什么其他错误不会被发现?当我们有连接问题,或文件不存在?据我所见,如果
,回调函数不会执行try
例如,未被触发。但它仍然存在 - 我仍然得到同样的错误 - req.addEventListener("load")
。
这是什么意思 - &#34;因为对Error: That was unexpected (line 13)
的调用立即返回&#34;而不会被捕获异常?
谢谢。
答案 0 :(得分:2)
您的backgroundReadFile
函数包含两部分:同步部分和异步部分:
function backgroundReadFile(url, callback) {
var req = new XMLHttpRequest(); // Synchronous
req.open("GET", url, true); // Synchronous
req.addEventListener("load", function() { // Synchronous
if (req.status < 400) // *A*synchronous
callback(req.responseText); // *A*synchronous
});
req.send(null); // Synchronous
}
您的try
/ catch
在调用它时,该函数的同步部分引发的错误是非常正确的。
异步部分中的错误不会被try
/ catch
捕获,因为有人告诉你,到那时控制流已经移动了
因此,如果它可能从同步代码中抛出,那么可能在该函数的调用周围有一个try
/ catch
是完全合理的。
附注:如果您要使用回调样式,则应始终回调,以便使用您的函数的代码知道该过程已完成。一种方式是将err
参数作为第一个参数传递给回调,如果没有错误则使用null
,然后将任何数据作为第二个参数(这通常称为& #34; Node.js回调样式&#34;)。但在现代环境中,更好的选择是使用Promise
。你可以用这样的最小改变来做到这一点:
function backgroundReadFile(url) {
return new Promsie(function(resolve, reject) {
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.addEventListener("load", function() {
if (req.status < 400) {
resolve(req.responseText);
} else {
reject(new Error({status: req.status}));
});
req.addEventListener("error", reject);
req.send(null);
});
}
...你这样使用:
backgroundReadFile(url)
.then(function(text) {
// Use the text
})
.catch(function(err) {
// Handle error
});
但在XMLHttpRequest
的特定情况下,您可以使用fetch
代替,它已经为您提供了承诺:
function backgroundReadFile(url) {
return fetch(url).then(response => {
if (!response.ok) {
throw new Error({status: response.status});
}
return response.text();
});
}
答案 1 :(得分:1)
以下是对代码中发生的情况的逐步细分。
backgroundReadFile
被调用,有两个参数:"example/data.txt"
和匿名函数。backgroundReadFile
创建一个AJAX请求并调用send()
。这里是异步概念发挥作用的地方:实际的HTTP请求是立即发送而不是,而是放在一个队列中,一旦浏览器运行完它正在运行的任何代码就执行当下(即你的try-ctach块)。backgroundReadFile
已经完成了。执行返回到try-catch块。onload
事件处理程序 - 无论响应是什么(即成功或错误)。backgroundReadFile
的匿名函数作为onload
事件处理程序的一部分调用,并抛出Error
。但是,正如您现在所看到的,您的代码在try-catch块中不再是而不是,因此它不会被捕获。TL; DR:抛出错误的函数是在try-catch块中定义,但在之外执行。
此外,AJAX请求中的错误处理有两个方面:连接错误和服务器端错误。连接错误可以是请求超时或发送请求时可能发生的一些其他随机错误;这些可以分别在ontimeout
和onerror
事件处理程序中处理。但是,如果HTTP请求进入服务器并收到响应,则就XMLHttpRequest
而言,请求成功。例如,您可以检查status
的{{1}}属性(其中包含HTTP响应代码,例如200表示“确定”,404表示“未找到”等),并确定它是否成功。