使用带有回调函数的异步JavaScript尝试/捕获块

使用带有回调函数的异步JavaScript尝试/捕获块,javascript,error-handling,Javascript,Error Handling,我有一段代码: 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); }

我有一段代码:

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");
}
这很好。但是,有人告诉我:

在代码中,由于 调用
backgroundReadFile
会立即返回。控制然后离开
try
块,在 稍后

问题是:为什么其他错误不会在这里被发现?当我们有连接问题,或者文件不存在时?在我看来,如果

req.addEventListener("load") 
例如,不会触发。但它仍然存在-我仍然得到相同的错误-
错误:这是意外的(第13行)

这意味着什么——“由于对
backgroundReadFile
的调用立即返回,因此不会捕获异常”


谢谢。

您的
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
}
…您可以这样使用:

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
的特定情况下,您可以使用,这已经为您提供了一个承诺:

function backgroundReadFile(url) {
  return fetch(url).then(response => {
      if (!response.ok) {
          throw new Error({status: response.status});
      }
      return response.text();
  });
}

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
}
…您可以这样使用:

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
的特定情况下,您可以使用,这已经为您提供了一个承诺:

function backgroundReadFile(url) {
  return fetch(url).then(response => {
      if (!response.ok) {
          throw new Error({status: response.status});
      }
      return response.text();
  });
}

下面是代码中发生的情况的逐步分解

  • 代码进入try-catch块
  • 调用
    backgroundReadFile
    ,其中包含两个参数:
    “example/data.txt”
    ,以及一个匿名函数
  • backgroundReadFile
    创建AJAX请求并调用
    send()
    。这里是异步概念发挥作用的地方:实际的HTTP请求不是立即发送的,而是放置在一个队列中,在浏览器运行完当前正在运行的任何代码(即try-ctach块)后立即执行
  • backgroundReadFile
    就此结束。执行返回到try-catch块
  • 未遇到异常,因此跳过catch块
  • 包含try-catch块的代码已完成执行现在浏览器可以继续执行队列中的第一个异步操作,这是您的AJAX请求
  • HTTP请求被发送,一旦收到响应,就会触发
    onload
    事件处理程序——不管响应是什么(即成功还是错误)
  • 传递给
    backgroundReadFile
    的匿名函数将作为
    onload
    事件处理程序的一部分调用,并抛出
    错误。但是,正如您现在看到的,您的代码不再位于try-catch块中,因此它没有被捕获
  • TL;DR:抛出错误的函数是在try-catch块内部定义的,但在其外部执行


    此外,AJAX请求中的错误处理有两个方面:连接错误和服务器端错误。连接错误可以是请求超时或发送请求时可能发生的其他随机错误;这些可以分别在
    ontimeout
    onerror
    事件处理程序中处理。但是,如果HTTP请求发送到服务器并收到响应,那么就
    XMLHttpRequest
    而言,请求是成功的。例如,您可以检查
    XMLHttpRequest
    status
    属性(该属性包含HTTP响应代码,例如200表示“OK”,404表示“not found”,等等),并确定它是否算成功。

    下面是代码中发生的情况的逐步细分

  • 代码进入try-catch块
  • 调用
    backgroundReadFile
    ,其中包含两个参数:
    “example/data.txt”
    ,以及一个匿名函数
  • backgroundReadFile
    创建AJAX请求并调用
    send()
    。这里是异步概念发挥作用的地方:实际的HTTP请求不是立即发送的,而是放置在一个队列中,在浏览器运行完当前正在运行的任何代码(即try-ctach块)后立即执行
  • backgroundReadFile
    就此结束。执行返回到try-catch块
  • 未遇到异常,因此跳过catch块
  • 包含try-catch块的代码已完成执行现在浏览器可以继续执行队列中的第一个异步操作,这是您的AJAX请求
  • HTTP请求被发送,一旦收到响应,就会触发
    onload
    事件处理程序——不管响应是什么(即成功还是错误)
  • 传递给
    backgroundReadFile
    的匿名函数将作为
    onload
    事件处理程序的一部分调用,并抛出
    错误。但是,正如您现在看到的,您的代码不再位于try-catch块中,因此它没有被捕获
  • TL;DR:抛出错误的函数是在try-catch块内部定义的,但在其外部执行

    此外,AJAX请求中的错误处理有两个方面:连接错误和服务器端错误。连接错误可以是请求超时或发送请求时可能发生的其他随机错误;这些可以分别在
    ontimeout
    onerror
    事件处理程序中处理。但是,如果HTTP请求发送到服务器并收到响应,那么就
    XMLHttpRequest
    而言,请求是成功的。例如,您可以检查
    XMLHttpRequest
    status
    属性(其中包含HTTP响应代码,例如200表示“OK”,404)